aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/catalog/pg_aggregate.c3
-rw-r--r--src/backend/catalog/pg_proc.c200
-rw-r--r--src/backend/commands/functioncmds.c28
-rw-r--r--src/backend/commands/proclang.c20
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/equalfuncs.c4
-rw-r--r--src/backend/parser/gram.y16
-rw-r--r--src/backend/parser/keywords.c3
-rw-r--r--src/backend/utils/adt/sets.c3
-rw-r--r--src/bin/pg_dump/pg_dump.c40
-rw-r--r--src/include/catalog/catversion.h4
-rw-r--r--src/include/catalog/pg_language.h16
-rw-r--r--src/include/catalog/pg_proc.h10
-rw-r--r--src/include/nodes/parsenodes.h3
-rw-r--r--src/test/regress/input/create_function_1.source25
-rw-r--r--src/test/regress/output/create_function_1.source25
16 files changed, 306 insertions, 97 deletions
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index 1853acda73c..3a3d749e19d 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.47 2002/05/21 22:05:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_aggregate.c,v 1.48 2002/05/22 17:20:58 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -136,6 +136,7 @@ AggregateCreate(const char *aggName,
false, /* doesn't return a set */
finaltype, /* returnType */
INTERNALlanguageId, /* languageObjectId */
+ 0,
"aggregate_dummy", /* placeholder proc */
"-", /* probin */
true, /* isAgg */
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index 4d656d98ba2..e7421ef2077 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.73 2002/05/21 22:05:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.74 2002/05/22 17:20:58 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,6 +20,7 @@
#include "catalog/pg_language.h"
#include "catalog/pg_proc.h"
#include "executor/executor.h"
+#include "fmgr.h"
#include "miscadmin.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
@@ -32,6 +33,9 @@
static void checkretval(Oid rettype, List *queryTreeList);
+Datum fmgr_internal_validator(PG_FUNCTION_ARGS);
+Datum fmgr_c_validator(PG_FUNCTION_ARGS);
+Datum fmgr_sql_validator(PG_FUNCTION_ARGS);
/* ----------------------------------------------------------------
@@ -45,6 +49,7 @@ ProcedureCreate(const char *procedureName,
bool returnsSet,
Oid returnType,
Oid languageObjectId,
+ Oid languageValidator,
const char *prosrc,
const char *probin,
bool isAgg,
@@ -66,7 +71,6 @@ ProcedureCreate(const char *procedureName,
char nulls[Natts_pg_proc];
Datum values[Natts_pg_proc];
char replaces[Natts_pg_proc];
- List *querytree_list;
Oid typev[FUNC_MAX_ARGS];
Oid relid;
NameData procname;
@@ -126,12 +130,6 @@ ProcedureCreate(const char *procedureName,
}
}
- if (!OidIsValid(returnType))
- {
- if (languageObjectId == SQLlanguageId)
- elog(ERROR, "SQL functions cannot return type \"opaque\"");
- }
-
/*
* don't allow functions of complex types that have the same name as
* existing attributes of the type
@@ -142,65 +140,6 @@ ProcedureCreate(const char *procedureName,
elog(ERROR, "method %s already an attribute of type %s",
procedureName, format_type_be(typev[0]));
- /*
- * If this is a postquel procedure, we parse it here in order to be
- * sure that it contains no syntax errors. We should store the plan
- * in an Inversion file for use later, but for now, we just store the
- * procedure's text in the prosrc attribute.
- */
-
- if (languageObjectId == SQLlanguageId)
- {
- querytree_list = pg_parse_and_rewrite((char *) prosrc,
- typev,
- parameterCount);
- /* typecheck return value */
- checkretval(returnType, querytree_list);
- }
-
- /*
- * If this is an internal procedure, check that the given internal
- * function name (the 'prosrc' value) is a known builtin function.
- *
- * NOTE: in Postgres versions before 6.5, the SQL name of the created
- * function could not be different from the internal name, and
- * 'prosrc' wasn't used. So there is code out there that does CREATE
- * FUNCTION xyz AS '' LANGUAGE 'internal'. To preserve some modicum
- * of backwards compatibility, accept an empty 'prosrc' value as
- * meaning the supplied SQL function name.
- */
- if (languageObjectId == INTERNALlanguageId)
- {
- if (strlen(prosrc) == 0)
- prosrc = procedureName;
- if (fmgr_internal_function((char *) prosrc) == InvalidOid)
- elog(ERROR,
- "there is no built-in function named \"%s\"",
- prosrc);
- }
-
- /*
- * If this is a dynamically loadable procedure, make sure that the
- * library file exists, is loadable, and contains the specified link
- * symbol. Also check for a valid function information record.
- *
- * We used to perform these checks only when the function was first
- * called, but it seems friendlier to verify the library's validity at
- * CREATE FUNCTION time.
- */
- if (languageObjectId == ClanguageId)
- {
- void *libraryhandle;
-
- /* If link symbol is specified as "-", substitute procedure name */
- if (strcmp(prosrc, "-") == 0)
- prosrc = procedureName;
- (void) load_external_function((char *) probin,
- (char *) prosrc,
- true,
- &libraryhandle);
- (void) fetch_finfo_record(libraryhandle, (char *) prosrc);
- }
/*
* All seems OK; prepare the data to be inserted into pg_proc.
@@ -316,6 +255,14 @@ ProcedureCreate(const char *procedureName,
heap_close(rel, RowExclusiveLock);
+ /* Verify function body */
+ if (OidIsValid(languageValidator))
+ {
+ /* Advance command counter so recursive functions can be defined */
+ CommandCounterIncrement();
+ OidFunctionCall1(languageValidator, retval);
+ }
+
return retval;
}
@@ -454,3 +401,122 @@ checkretval(Oid rettype, List *queryTreeList)
heap_close(reln, AccessShareLock);
}
+
+
+
+/*
+ * Validator for internal functions
+ *
+ * Check that the given internal function name (the "prosrc" value) is
+ * a known builtin function.
+ */
+Datum
+fmgr_internal_validator(PG_FUNCTION_ARGS)
+{
+ Oid funcoid = PG_GETARG_OID(0);
+ HeapTuple tuple;
+ Form_pg_proc proc;
+ bool isnull;
+ Datum tmp;
+ char *prosrc;
+
+ tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup of function %u failed", funcoid);
+ proc = (Form_pg_proc) GETSTRUCT(tuple);
+
+ tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
+ if (isnull)
+ elog(ERROR, "null prosrc");
+ prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
+
+ if (fmgr_internal_function(prosrc) == InvalidOid)
+ elog(ERROR, "there is no built-in function named \"%s\"", prosrc);
+
+ ReleaseSysCache(tuple);
+ PG_RETURN_BOOL(true);
+}
+
+
+
+/*
+ * Validator for C language functions
+ *
+ * Make sure that the library file exists, is loadable, and contains
+ * the specified link symbol. Also check for a valid function
+ * information record.
+ */
+Datum
+fmgr_c_validator(PG_FUNCTION_ARGS)
+{
+ Oid funcoid = PG_GETARG_OID(0);
+ void *libraryhandle;
+ HeapTuple tuple;
+ Form_pg_proc proc;
+ bool isnull;
+ Datum tmp;
+ char *prosrc;
+ char *probin;
+
+ tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup of function %u failed", funcoid);
+ proc = (Form_pg_proc) GETSTRUCT(tuple);
+
+ tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
+ if (isnull)
+ elog(ERROR, "null prosrc");
+ prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
+
+ tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_probin, &isnull);
+ if (isnull)
+ elog(ERROR, "null probin");
+ probin = DatumGetCString(DirectFunctionCall1(textout, tmp));
+
+ (void) load_external_function(probin, prosrc, true, &libraryhandle);
+ (void) fetch_finfo_record(libraryhandle, prosrc);
+
+ ReleaseSysCache(tuple);
+ PG_RETURN_BOOL(true);
+}
+
+
+
+/*
+ * Validator for SQL language functions
+ *
+ * Parse it here in order to be sure that it contains no syntax
+ * errors.
+ */
+Datum
+fmgr_sql_validator(PG_FUNCTION_ARGS)
+{
+ Oid funcoid = PG_GETARG_OID(0);
+ HeapTuple tuple;
+ Form_pg_proc proc;
+ List *querytree_list;
+ bool isnull;
+ Datum tmp;
+ char *prosrc;
+
+ tuple = SearchSysCache(PROCOID, funcoid, 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "cache lookup of function %u failed", funcoid);
+
+ proc = (Form_pg_proc) GETSTRUCT(tuple);
+
+ if (!OidIsValid(proc->prorettype))
+ elog(ERROR, "SQL functions cannot return type \"opaque\"");
+
+ tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull);
+ if (isnull)
+ elog(ERROR, "null prosrc");
+
+ prosrc = DatumGetCString(DirectFunctionCall1(textout, tmp));
+
+ querytree_list = pg_parse_and_rewrite(prosrc, proc->proargtypes, proc->pronargs);
+ checkretval(proc->prorettype, querytree_list);
+
+ ReleaseSysCache(tuple);
+ PG_RETURN_BOOL(true);
+}
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 06870b0d3d2..a619a71b435 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.5 2002/05/18 13:47:59 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/functioncmds.c,v 1.6 2002/05/22 17:20:58 petere Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@@ -388,6 +388,7 @@ CreateFunction(CreateFunctionStmt *stmt)
char *language;
char languageName[NAMEDATALEN];
Oid languageOid;
+ Oid languageValidator;
char *funcname;
Oid namespaceId;
AclResult aclresult;
@@ -457,6 +458,8 @@ CreateFunction(CreateFunctionStmt *stmt)
aclcheck_error(ACLCHECK_NO_PRIV, NameStr(languageStruct->lanname));
}
+ languageValidator = languageStruct->lanvalidator;
+
ReleaseSysCache(languageTuple);
/*
@@ -477,6 +480,28 @@ CreateFunction(CreateFunctionStmt *stmt)
interpret_AS_clause(languageOid, languageName, as_clause,
&prosrc_str, &probin_str);
+ if (languageOid == INTERNALlanguageId)
+ {
+ /*
+ * In PostgreSQL versions before 6.5, the SQL name of the
+ * created function could not be different from the internal
+ * name, and "prosrc" wasn't used. So there is code out there
+ * that does CREATE FUNCTION xyz AS '' LANGUAGE 'internal'.
+ * To preserve some modicum of backwards compatibility, accept
+ * an empty "prosrc" value as meaning the supplied SQL
+ * function name.
+ */
+ if (strlen(prosrc_str) == 0)
+ prosrc_str = funcname;
+ }
+
+ if (languageOid == ClanguageId)
+ {
+ /* If link symbol is specified as "-", substitute procedure name */
+ if (strcmp(prosrc_str, "-") == 0)
+ prosrc_str = funcname;
+ }
+
/*
* And now that we have all the parameters, and know we're permitted
* to do so, go ahead and create the function.
@@ -487,6 +512,7 @@ CreateFunction(CreateFunctionStmt *stmt)
returnsSet,
prorettype,
languageOid,
+ languageValidator,
prosrc_str, /* converted to text later */
probin_str, /* converted to text later */
false, /* not an aggregate */
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 6cabbf0ec13..626c05f59cd 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.32 2002/05/21 22:05:54 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/proclang.c,v 1.33 2002/05/22 17:20:58 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -21,6 +21,7 @@
#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"
@@ -39,7 +40,7 @@ void
CreateProceduralLanguage(CreatePLangStmt *stmt)
{
char languageName[NAMEDATALEN];
- Oid procOid;
+ Oid procOid, valProcOid;
Oid typev[FUNC_MAX_ARGS];
char nulls[Natts_pg_language];
Datum values[Natts_pg_language];
@@ -76,9 +77,21 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
elog(ERROR, "PL handler function %s() doesn't exist",
NameListToString(stmt->plhandler));
if (get_func_rettype(procOid) != InvalidOid)
- elog(ERROR, "PL handler function %s() isn't of return type Opaque",
+ elog(ERROR, "PL handler function %s() does not return type \"opaque\"",
NameListToString(stmt->plhandler));
+ /* validate the validator function */
+ if (stmt->plvalidator)
+ {
+ typev[0] = OIDOID;
+ valProcOid = LookupFuncName(stmt->plvalidator, 1, typev);
+ if (!OidIsValid(valProcOid))
+ elog(ERROR, "PL validator function %s(oid) doesn't exist",
+ NameListToString(stmt->plvalidator));
+ }
+ else
+ valProcOid = 0;
+
/*
* Insert the new language into pg_language
*/
@@ -93,6 +106,7 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
values[i++] = BoolGetDatum(true); /* lanispl */
values[i++] = BoolGetDatum(stmt->pltrusted);
values[i++] = ObjectIdGetDatum(procOid);
+ values[i++] = ObjectIdGetDatum(valProcOid);
values[i++] = DirectFunctionCall1(textin,
CStringGetDatum(stmt->plcompiler));
nulls[i] = 'n'; /* lanacl */
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 1f0cc11934f..5bc16dc9b82 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.187 2002/05/17 18:32:52 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.188 2002/05/22 17:20:58 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2418,6 +2418,7 @@ _copyCreatePLangStmt(CreatePLangStmt *from)
if (from->plname)
newnode->plname = pstrdup(from->plname);
Node_Copy(from, newnode, plhandler);
+ Node_Copy(from, newnode, plvalidator);
if (from->plcompiler)
newnode->plcompiler = pstrdup(from->plcompiler);
newnode->pltrusted = from->pltrusted;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index f48d6d033f4..b4f576fc881 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.134 2002/05/17 18:32:52 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.135 2002/05/22 17:20:59 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1252,6 +1252,8 @@ _equalCreatePLangStmt(CreatePLangStmt *a, CreatePLangStmt *b)
return false;
if (!equal(a->plhandler, b->plhandler))
return false;
+ if (!equal(a->plvalidator, b->plvalidator))
+ return false;
if (!equalstr(a->plcompiler, b->plcompiler))
return false;
if (a->pltrusted != b->pltrusted)
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 999910161d0..d1109b58a7e 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.318 2002/05/19 15:16:55 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.319 2002/05/22 17:20:59 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -182,7 +182,7 @@ static void doNegateFloat(Value *v);
index_name, name, function_name, file_name
%type <list> func_name, handler_name, qual_Op, qual_all_Op, OptUseOp,
- opt_class
+ opt_class, opt_validator
%type <range> qualified_name, OptConstrFromTable
@@ -375,7 +375,7 @@ static void doNegateFloat(Value *v);
UNENCRYPTED, UNION, UNIQUE, UNKNOWN, UNLISTEN, UNTIL, UPDATE, USAGE,
USER, USING,
- VACUUM, VALID, VALUES, VARCHAR, VARYING, VERBOSE, VERSION, VIEW, VOLATILE,
+ VACUUM, VALID, VALIDATOR, VALUES, VARCHAR, VARYING, VERBOSE, VERSION, VIEW, VOLATILE,
WHEN, WHERE, WITH, WITHOUT, WORK,
YEAR_P,
ZONE
@@ -1835,12 +1835,13 @@ IntegerOnly: Iconst
*****************************************************************************/
CreatePLangStmt: CREATE opt_trusted opt_procedural LANGUAGE ColId_or_Sconst
- HANDLER handler_name opt_lancompiler
+ HANDLER handler_name opt_validator opt_lancompiler
{
CreatePLangStmt *n = makeNode(CreatePLangStmt);
n->plname = $5;
n->plhandler = $7;
- n->plcompiler = $8;
+ n->plvalidator = $8;
+ n->plcompiler = $9;
n->pltrusted = $2;
$$ = (Node *)n;
}
@@ -1864,6 +1865,10 @@ opt_lancompiler: LANCOMPILER Sconst { $$ = $2; }
| /*EMPTY*/ { $$ = ""; }
;
+opt_validator: VALIDATOR handler_name { $$ = $2; }
+ | /*EMPTY*/ { $$ = NULL; }
+ ;
+
DropPLangStmt: DROP opt_procedural LANGUAGE ColId_or_Sconst
{
DropPLangStmt *n = makeNode(DropPLangStmt);
@@ -6357,6 +6362,7 @@ unreserved_keyword:
| USAGE
| VACUUM
| VALID
+ | VALIDATOR
| VALUES
| VARYING
| VERSION
diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c
index 36900127ea8..2cf91572a00 100644
--- a/src/backend/parser/keywords.c
+++ b/src/backend/parser/keywords.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.110 2002/05/17 18:32:52 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.111 2002/05/22 17:20:59 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -292,6 +292,7 @@ static const ScanKeyword ScanKeywords[] = {
{"using", USING},
{"vacuum", VACUUM},
{"valid", VALID},
+ {"validator", VALIDATOR},
{"values", VALUES},
{"varchar", VARCHAR},
{"varying", VARYING},
diff --git a/src/backend/utils/adt/sets.c b/src/backend/utils/adt/sets.c
index 298bdbdec82..e93ed50ff0a 100644
--- a/src/backend/utils/adt/sets.c
+++ b/src/backend/utils/adt/sets.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.44 2002/05/18 13:47:59 petere Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/Attic/sets.c,v 1.45 2002/05/22 17:21:00 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -58,6 +58,7 @@ SetDefine(char *querystr, Oid elemType)
true, /* returnsSet */
elemType, /* returnType */
SQLlanguageId, /* language */
+ SQLvalidatorId,
querystr, /* prosrc */
fileName, /* probin */
false, /* not aggregate */
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 5e1d3ecd0dc..2e0295fc844 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -22,7 +22,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.263 2002/05/19 10:08:25 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.264 2002/05/22 17:21:00 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3108,6 +3108,7 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
int i_lanname;
int i_lanpltrusted;
int i_lanplcallfoid;
+ int i_lanvalidator = -1;
int i_lancompiler;
int i_lanacl = -1;
char *lanoid;
@@ -3115,10 +3116,12 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
char *lancompiler;
char *lanacl;
const char *lanplcallfoid;
+ const char *lanvalidator;
const char *((*deps)[]);
int depIdx;
int i,
- fidx;
+ fidx,
+ vidx = -1;
/* Make sure we are in proper schema */
selectSourceSchema("pg_catalog");
@@ -3142,7 +3145,10 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
i_lancompiler = PQfnumber(res, "lancompiler");
i_oid = PQfnumber(res, "oid");
if (fout->remoteVersion >= 70300)
+ {
+ i_lanvalidator = PQfnumber(res, "lanvalidator");
i_lanacl = PQfnumber(res, "lanacl");
+ }
for (i = 0; i < ntups; i++)
{
@@ -3151,9 +3157,15 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
lanname = PQgetvalue(res, i, i_lanname);
lancompiler = PQgetvalue(res, i, i_lancompiler);
if (fout->remoteVersion >= 70300)
+ {
+ lanvalidator = PQgetvalue(res, i, i_lanvalidator);
lanacl = PQgetvalue(res, i, i_lanacl);
+ }
else
- lanacl = "{=U}";
+ {
+ lanvalidator = "0";
+ lanacl = "{=U}";
+ }
fidx = findFuncByOid(finfo, numFuncs, lanplcallfoid);
if (fidx < 0)
@@ -3163,6 +3175,17 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
exit_nicely();
}
+ if (strcmp(lanvalidator, "0") != 0)
+ {
+ vidx = findFuncByOid(finfo, numFuncs, lanvalidator);
+ if (vidx < 0)
+ {
+ write_msg(NULL, "validator procedure for procedural language %s not found\n",
+ lanname);
+ exit_nicely();
+ }
+ }
+
/*
* Current theory is to dump PLs iff their underlying functions
* will be dumped (are in a dumpable namespace, or have a non-system
@@ -3178,7 +3201,7 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
resetPQExpBuffer(delqry);
/* Make a dependency to ensure function is dumped first */
- deps = malloc(sizeof(char *) * 2);
+ deps = malloc(sizeof(char *) * (2 + (strcmp(lanvalidator, "0")!=0) ? 1 : 0));
depIdx = 0;
(*deps)[depIdx++] = strdup(lanplcallfoid);
@@ -3189,8 +3212,15 @@ dumpProcLangs(Archive *fout, FuncInfo finfo[], int numFuncs)
(PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ?
"TRUSTED " : "",
fmtId(lanname, force_quotes));
- appendPQExpBuffer(defqry, " HANDLER %s;\n",
+ appendPQExpBuffer(defqry, " HANDLER %s",
fmtId(finfo[fidx].proname, force_quotes));
+ if (strcmp(lanvalidator, "0")!=0)
+ {
+ appendPQExpBuffer(defqry, " VALIDATOR %s",
+ fmtId(finfo[vidx].proname, force_quotes));
+ (*deps)[depIdx++] = strdup(lanvalidator);
+ }
+ appendPQExpBuffer(defqry, ";\n");
(*deps)[depIdx++] = NULL; /* End of List */
diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h
index 4c9b2fd83a3..bd861396210 100644
--- a/src/include/catalog/catversion.h
+++ b/src/include/catalog/catversion.h
@@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: catversion.h,v 1.132 2002/05/18 13:48:00 petere Exp $
+ * $Id: catversion.h,v 1.133 2002/05/22 17:21:01 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -53,6 +53,6 @@
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 200205181
+#define CATALOG_VERSION_NO 200205221
#endif
diff --git a/src/include/catalog/pg_language.h b/src/include/catalog/pg_language.h
index d7f48628e93..e9eec5f4845 100644
--- a/src/include/catalog/pg_language.h
+++ b/src/include/catalog/pg_language.h
@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_language.h,v 1.16 2002/02/18 23:11:35 petere Exp $
+ * $Id: pg_language.h,v 1.17 2002/05/22 17:21:01 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@@ -37,6 +37,7 @@ CATALOG(pg_language)
bool lanispl; /* Is a procedural language */
bool lanpltrusted; /* PL is trusted */
Oid lanplcallfoid; /* Call handler for PL */
+ Oid lanvalidator; /* optional validation function */
text lancompiler; /* VARIABLE LENGTH FIELD */
aclitem lanacl[1]; /* Access privileges */
} FormData_pg_language;
@@ -52,26 +53,27 @@ typedef FormData_pg_language *Form_pg_language;
* compiler constants for pg_language
* ----------------
*/
-#define Natts_pg_language 6
+#define Natts_pg_language 7
#define Anum_pg_language_lanname 1
#define Anum_pg_language_lanispl 2
#define Anum_pg_language_lanpltrusted 3
#define Anum_pg_language_lanplcallfoid 4
-#define Anum_pg_language_lancompiler 5
-#define Anum_pg_language_lanacl 6
+#define Anum_pg_language_lanvalidator 5
+#define Anum_pg_language_lancompiler 6
+#define Anum_pg_language_lanacl 7
/* ----------------
* initial contents of pg_language
* ----------------
*/
-DATA(insert OID = 12 ( "internal" f f 0 "n/a" _null_ ));
+DATA(insert OID = 12 ( "internal" f f 0 2246 "n/a" _null_ ));
DESCR("Built-in functions");
#define INTERNALlanguageId 12
-DATA(insert OID = 13 ( "c" f f 0 "/bin/cc" _null_ ));
+DATA(insert OID = 13 ( "c" f f 0 2247 "/bin/cc" _null_ ));
DESCR("Dynamically-loaded C functions");
#define ClanguageId 13
-DATA(insert OID = 14 ( "sql" f t 0 "postgres" _null_ ));
+DATA(insert OID = 14 ( "sql" f t 0 2248 "postgres" _null_ ));
DESCR("SQL-language functions");
#define SQLlanguageId 14
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index c7f829c3153..2cc1f8aac1f 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pg_proc.h,v 1.238 2002/05/20 23:51:43 tgl Exp $
+ * $Id: pg_proc.h,v 1.239 2002/05/22 17:21:01 petere Exp $
*
* NOTES
* The script catalog/genbki.sh reads this file and generates .bki
@@ -2962,6 +2962,13 @@ DESCR("(internal)");
DATA(insert OID = 2221 ( regtypeout PGNSP PGUID 12 f f f t f s 1 23 "0" 100 0 0 100 regtypeout - _null_ ));
DESCR("(internal)");
+DATA(insert OID = 2246 ( fmgr_internal_validator PGNSP PGUID 12 f f f t f s 1 26 "23" 100 0 0 100 fmgr_internal_validator - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2247 ( fmgr_c_validator PGNSP PGUID 12 f f f t f s 1 26 "23" 100 0 0 100 fmgr_c_validator - _null_ ));
+DESCR("(internal)");
+DATA(insert OID = 2248 ( fmgr_sql_validator PGNSP PGUID 12 f f f t f s 1 26 "23" 100 0 0 100 fmgr_sql_validator - _null_ ));
+DESCR("(internal)");
+#define SQLvalidatorId 2248
/*
* Symbolic values for provolatile column: these indicate whether the result
@@ -2985,6 +2992,7 @@ extern Oid ProcedureCreate(const char *procedureName,
bool returnsSet,
Oid returnType,
Oid languageObjectId,
+ Oid languageValidator,
const char *prosrc,
const char *probin,
bool isAgg,
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 3466e125982..f7ea60ac802 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.178 2002/05/17 18:32:52 petere Exp $
+ * $Id: parsenodes.h,v 1.179 2002/05/22 17:21:01 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -990,6 +990,7 @@ typedef struct CreatePLangStmt
NodeTag type;
char *plname; /* PL name */
List *plhandler; /* PL call handler function (qual. name) */
+ List *plvalidator; /* optional validator function (qual. name) */
char *plcompiler; /* lancompiler text */
bool pltrusted; /* PL is trusted */
} CreatePLangStmt;
diff --git a/src/test/regress/input/create_function_1.source b/src/test/regress/input/create_function_1.source
index 6d91674cd56..14ae6ff2bbb 100644
--- a/src/test/regress/input/create_function_1.source
+++ b/src/test/regress/input/create_function_1.source
@@ -42,3 +42,28 @@ CREATE FUNCTION set_ttdummy (int4)
AS '@abs_builddir@/regress@DLSUFFIX@'
LANGUAGE 'C';
+-- Things that shouldn't work:
+
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'SELECT ''not an integer'';';
+
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'not even SQL';
+
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'SELECT 1, 2, 3;';
+
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'SELECT $2;';
+
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'a', 'b';
+
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE c
+ AS 'nosuchfile';
+
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE c
+ AS '@abs_builddir@/regress@DLSUFFIX@', 'nosuchsymbol';
+
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE internal
+ AS 'nosuch';
diff --git a/src/test/regress/output/create_function_1.source b/src/test/regress/output/create_function_1.source
index ded580ee7c4..2f59a693319 100644
--- a/src/test/regress/output/create_function_1.source
+++ b/src/test/regress/output/create_function_1.source
@@ -34,3 +34,28 @@ CREATE FUNCTION set_ttdummy (int4)
RETURNS int4
AS '@abs_builddir@/regress@DLSUFFIX@'
LANGUAGE 'C';
+-- Things that shouldn't work:
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'SELECT ''not an integer'';';
+ERROR: return type mismatch in function: declared to return integer, returns "unknown"
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'not even SQL';
+ERROR: parser: parse error at or near "not"
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'SELECT 1, 2, 3;';
+ERROR: function declared to return integer returns multiple columns in final SELECT
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'SELECT $2;';
+ERROR: Parameter '$2' is out of range
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE sql
+ AS 'a', 'b';
+ERROR: CREATE FUNCTION: only one AS item needed for sql language
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE c
+ AS 'nosuchfile';
+ERROR: stat failed on file 'nosuchfile': No such file or directory
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE c
+ AS '@abs_builddir@/regress@DLSUFFIX@', 'nosuchsymbol';
+ERROR: Can't find function nosuchsymbol in file @abs_builddir@/regress@DLSUFFIX@
+CREATE FUNCTION test1 (int) RETURNS int LANGUAGE internal
+ AS 'nosuch';
+ERROR: there is no built-in function named "nosuch"