diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/backend/catalog/pg_aggregate.c | 3 | ||||
-rw-r--r-- | src/backend/catalog/pg_proc.c | 200 | ||||
-rw-r--r-- | src/backend/commands/functioncmds.c | 28 | ||||
-rw-r--r-- | src/backend/commands/proclang.c | 20 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 3 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 4 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 16 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 3 | ||||
-rw-r--r-- | src/backend/utils/adt/sets.c | 3 | ||||
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 40 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 4 | ||||
-rw-r--r-- | src/include/catalog/pg_language.h | 16 | ||||
-rw-r--r-- | src/include/catalog/pg_proc.h | 10 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 3 | ||||
-rw-r--r-- | src/test/regress/input/create_function_1.source | 25 | ||||
-rw-r--r-- | src/test/regress/output/create_function_1.source | 25 |
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" |