aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-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
9 files changed, 199 insertions, 81 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 */