From 94bdc4855cf8db8a2df83a19d18ce72fd5eb2691 Mon Sep 17 00:00:00 2001 From: Peter Eisentraut Date: Fri, 17 May 2002 18:32:52 +0000 Subject: [PATCH] Extend syntax of CREATE FUNCTION to resemble SQL99. --- doc/src/sgml/ref/create_function.sgml | 348 +++++++++++++++----------- doc/src/sgml/release.sgml | 3 +- src/backend/commands/functioncmds.c | 151 +++++++++-- src/backend/nodes/copyfuncs.c | 15 +- src/backend/nodes/equalfuncs.c | 14 +- src/backend/parser/gram.y | 142 +++++++++-- src/backend/parser/keywords.c | 13 +- src/backend/tcop/postgres.c | 6 +- src/backend/tcop/utility.c | 6 +- src/bin/pg_dump/pg_dump.c | 60 ++--- src/include/commands/defrem.h | 4 +- src/include/nodes/nodes.h | 4 +- src/include/nodes/parsenodes.h | 9 +- 13 files changed, 504 insertions(+), 271 deletions(-) diff --git a/doc/src/sgml/ref/create_function.sgml b/doc/src/sgml/ref/create_function.sgml index 18961336531..495a1331464 100644 --- a/doc/src/sgml/ref/create_function.sgml +++ b/doc/src/sgml/ref/create_function.sgml @@ -1,5 +1,5 @@ @@ -17,13 +17,13 @@ $Header: /cvsroot/pgsql/doc/src/sgml/ref/create_function.sgml,v 1.37 2002/04/23 CREATE [ OR REPLACE ] FUNCTION name ( [ argtype [, ...] ] ) RETURNS rettype - AS 'definition' - LANGUAGE langname - [ WITH ( attribute [, ...] ) ] -CREATE [ OR REPLACE ] FUNCTION name ( [ argtype [, ...] ] ) - RETURNS rettype - AS 'obj_file', 'link_symbol' - LANGUAGE langname + { LANGUAGE langname + | IMMUTABLE | STABLE | VOLATILE + | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT + | IMPLICIT CAST + | AS 'definition' + | AS 'obj_file', 'link_symbol' + } ... [ WITH ( attribute [, ...] ) ] @@ -33,8 +33,13 @@ CREATE [ OR REPLACE ] FUNCTION name CREATE FUNCTION defines a new function. - CREATE OR REPLACE FUNCTION will either create - a new function, or replace an existing definition. + CREATE OR REPLACE FUNCTION will either create a + new function, or replace an existing definition. + + + + The user that creates the function becomes the owner of the function. + Parameters @@ -81,7 +86,7 @@ CREATE [ OR REPLACE ] FUNCTION name - The return data type. The output type may be specified as a + The return data type. The return type may be specified as a base type, complex type, setof type, opaque, or the same as the type of an existing column. @@ -95,6 +100,105 @@ CREATE [ OR REPLACE ] FUNCTION name + + langname + + + + The name of the language that the function is implemented in. + May be SQL, C, + internal, or the name of a user-defined + procedural language. (See also .) For backward compatibility, + the name may be enclosed by single quotes. + + + + + + IMMUTABLE + STABLE + VOLATILE + + + + These attributes inform the system whether it is safe to + replace multiple evaluations of the function with a single + evaluation, for run-time optimization. At most one choice + should be specified. If none of these appear, + VOLATILE is the default assumption. + + + + IMMUTABLE indicates that the function always + returns the same result when given the same argument values; that + is, it does not do database lookups or otherwise use information not + directly present in its parameter list. If this option is given, + any call of the function with all-constant arguments can be + immediately replaced with the function value. + + + + STABLE indicates that within a single table scan + the function will consistently + return the same result for the same argument values, but that its + result could change across SQL statements. This is the appropriate + selection for functions whose results depend on database lookups, + parameter variables (such as the current time zone), etc. Also note + that the CURRENT_TIMESTAMP family of functions qualify + as stable, since their values do not change within a transaction. + + + + VOLATILE indicates that the function value can + change even within a single table scan, so no optimizations can be + made. Relatively few database functions are volatile in this sense; + some examples are random(), currval(), + timeofday(). Note that any function that has side-effects + must be classified volatile, even if its result is quite predictable, + to prevent calls from being optimized away; an example is + setval(). + + + + + + CALLED ON NULL INPUT + RETURNS NULL ON NULL INPUT + STRICT + + + + CALLED ON NULL INPUT (the default) indicates + that the function will be called normally when some of its + arguments are null. It is then the function author's + responsibility to check for NULLs if necessary and respond + appropriately. + + + + RETURNS NULL ON NULL INPUT or + STRICT indicates that the function always + returns NULL whenever any of its arguments are NULL. If this + parameter is specified, the function is not executed when there + are NULL arguments; instead a NULL result is assumed + automatically. + + + + + + IMPLICIT CAST + + + + Indicates that the function may be used for implicit type + conversions. See for more detail. + + + + definition @@ -125,116 +229,56 @@ CREATE [ OR REPLACE ] FUNCTION name - - langname - - - - May be SQL, C, - internal, or plname, where plname is the name of a - created procedural language. See - - for details. For backward compatibility, the name may be - enclosed by single quotes. - - - - attribute - An optional piece of information about the function, used for - optimization. See below for details. - - - + The historical way to specify optional pieces of information + about the function. The following attributes may appear here: + + + + isStrict + + + Equivalent to STRICT or RETURNS NULL ON NULL INPUT + + + + + + isImmutable + isCachable + isStable + isVolatile + + + Equivalent to IMMUTABLE, + STABLE, VOLATILE. + isCachable is an obsolete equivalent of + isImmutable; it's still accepted for + backwards-compatibility reasons. + + + + + + implicitCoercion + + + Same as IMPLICIT CAST + + + + + + Attribute names are not case-sensitive. + + + - - - - The user that creates the function becomes the owner of the function. - - - - The following attributes may appear in the WITH clause: - - - - isStrict - - - indicates that the function always - returns NULL whenever any of its arguments are NULL. If this - attribute is specified, the function is not executed when there - are NULL arguments; instead a NULL result is assumed automatically. - When is not specified, the function will - be called for NULL inputs. It is then the function author's - responsibility to check for NULLs if necessary and respond - appropriately. - - - - - - isImmutable - isCachable - isStable - isVolatile - - - These attributes inform the system whether it is safe to replace - multiple evaluations of the function with a single evaluation. - At most one choice should be specified. (If none of these appear, - is the default assumption.) - indicates that the function always - returns the same result when given the same argument values; that - is, it does not do database lookups or otherwise use information not - directly present in its parameter list. If this option is given, - any call of the function with all-constant arguments can be - immediately replaced with the function value. - is an - obsolete equivalent of ; it's still - accepted for backwards-compatibility reasons. - indicates that within a single table scan - the function will consistently - return the same result for the same argument values, but that its - result could change across SQL statements. This is the appropriate - selection for functions whose results depend on database lookups, - parameter variables (such as the current timezone), etc. Also note - that the CURRENT_TIMESTAMP family of functions qualify - as stable, since their values do not change within a transaction. - indicates that the function value can - change even within a single table scan, so no optimizations can be - made. Relatively few database functions are volatile in this sense; - some examples are random(), currval(), - timeofday(). Note that any function that has side-effects - must be classified volatile, even if its result is quite predictable, - to prevent calls from being optimized away; an example is - setval(). - - - - - - implicitCoercion - - - indicates that the function - may be used for implicit type conversions. - See for more detail. - - - - - - Attribute names are not case-sensitive. - @@ -328,21 +372,18 @@ CREATE [ OR REPLACE ] FUNCTION name - - - 2002-04-11 - - - Type Coercion Functions + <refsect1 id="sql-createfunction-cast-function"> + <title id="sql-createfunction-cast-functions-title"> + Type Cast Functions - A function that has one parameter and is named the same as its output - datatype (including the schema name) is considered to be a type - coercion function: it can be invoked to convert a value of its input - datatype into a value + A function that has one argument and is named the same as its return + data type (including the schema name) is considered to be a type + casting function: it can be invoked to convert a value of its input + data type into a value of its output datatype. For example, - SELECT CAST(42 AS text); +SELECT CAST(42 AS text); converts the integer constant 42 to text by invoking a function text(int4), if such a function exists and returns type @@ -350,31 +391,33 @@ CREATE [ OR REPLACE ] FUNCTION name - If a potential coercion function is marked implicitCoercion, - then it can be invoked in any context where the conversion it defines - is required. Coercion functions not so marked can be invoked only by - explicit CAST, - x::typename, - or typename(x) constructs. - For example, supposing that foo.f1 is a column of type text, then + If a potential cast function is marked IMPLICIT CAST, + then it can be invoked implicitly in any context where the + conversion it defines is required. Cast functions not so marked + can be invoked only by explicit CAST, + x::typename, or + typename(x) constructs. For + example, supposing that foo.f1 is a column of + type text, then - INSERT INTO foo(f1) VALUES(42); +INSERT INTO foo(f1) VALUES(42); will be allowed if text(int4) is marked - implicitCoercion, otherwise not. + IMPLICIT CAST, otherwise not. - It is wise to be conservative about marking coercion functions as - implicit coercions. An overabundance of implicit coercion paths - can cause PostgreSQL to choose surprising - interpretations of commands, - or to be unable to resolve commands at all because there are multiple - possible interpretations. A good rule of thumb is to make coercions - implicitly invokable only for information-preserving transformations - between types in the same general type category. For example, int2 - to int4 coercion can reasonably be implicit, but be wary of marking - int4 to text or float8 to int4 as implicit coercions. + It is wise to be conservative about marking cast functions as + implicit casts. An overabundance of implicit casting paths can + cause PostgreSQL to choose surprising + interpretations of commands, or to be unable to resolve commands at + all because there are multiple possible interpretations. A good + rule of thumb is to make cast implicitly invokable only for + information-preserving transformations between types in the same + general type category. For example, int2 to + int4 casts can reasonably be implicit, but be wary of + marking int4 to text or + float8 to int4 as implicit casts. @@ -403,7 +446,7 @@ SELECT one() AS answer; user-created shared library named funcs.so (the extension may vary across platforms). The shared library file is sought in the server's dynamic library search path. This particular routine calculates - a check digit and returns TRUE if the check digit in the function + a check digit and returns true if the check digit in the function parameters is correct. It is intended for use in a CHECK constraint. @@ -422,7 +465,7 @@ CREATE TABLE product ( - This example creates a function that does type conversion from the + The next example creates a function that does type conversion from the user-defined type complex to the built-in type point. The function is implemented by a dynamically loaded object that was compiled from C source (we illustrate the now-deprecated alternative @@ -436,7 +479,7 @@ CREATE TABLE product ( CREATE FUNCTION point(complex) RETURNS point AS '/home/bernie/pgsql/lib/complex.so', 'complex_to_point' - LANGUAGE C WITH (isStrict); + LANGUAGE C STRICT; The C declaration of the function could be: @@ -466,7 +509,7 @@ Point * complex_to_point (Complex *z) A CREATE FUNCTION command is defined in SQL99. The PostgreSQL version is similar but - not compatible. The attributes are not portable, neither are the + not fully compatible. The attributes are not portable, neither are the different available languages. @@ -476,10 +519,11 @@ Point * complex_to_point (Complex *z) See Also - , - , - , - , + , + , + , + , + , PostgreSQL Programmer's Guide diff --git a/doc/src/sgml/release.sgml b/doc/src/sgml/release.sgml index 889f2203f69..9b75049938a 100644 --- a/doc/src/sgml/release.sgml +++ b/doc/src/sgml/release.sgml @@ -1,5 +1,5 @@ @@ -24,6 +24,7 @@ CDATA means the content is "SGML-free", so you can write without worries about funny characters. --> defname, "as")==0) + { + if (as_item) + elog(ERROR, "conflicting or redundant options"); + as_item = defel; + } + else if (strcmp(defel->defname, "language")==0) + { + if (language_item) + elog(ERROR, "conflicting or redundant options"); + language_item = defel; + } + else if (strcmp(defel->defname, "volatility")==0) + { + if (volatility_item) + elog(ERROR, "conflicting or redundant options"); + volatility_item = defel; + } + else if (strcmp(defel->defname, "strict")==0) + { + if (strict_item) + elog(ERROR, "conflicting or redundant options"); + strict_item = defel; + } + else if (strcmp(defel->defname, "security")==0) + { + if (security_item) + elog(ERROR, "conflicting or redundant options"); + security_item = defel; + } + else if (strcmp(defel->defname, "implicit")==0) + { + if (implicit_item) + elog(ERROR, "conflicting or redundant options"); + implicit_item = defel; + } + else + elog(ERROR, "invalid CREATE FUNCTION option"); + } + + if (as_item) + *as = (List *)as_item->arg; + else + elog(ERROR, "no function body specified"); + + if (language_item) + *language = strVal(language_item->arg); + else + elog(ERROR, "no language specified"); + + if (volatility_item) + { + if (strcmp(strVal(volatility_item->arg), "immutable")==0) + *volatility_p = PROVOLATILE_IMMUTABLE; + else if (strcmp(strVal(volatility_item->arg), "stable")==0) + *volatility_p = PROVOLATILE_STABLE; + else if (strcmp(strVal(volatility_item->arg), "volatile")==0) + *volatility_p = PROVOLATILE_VOLATILE; + else + elog(ERROR, "invalid volatility"); + } + + if (strict_item) + *strict_p = intVal(strict_item->arg); + if (security_item) + *security_definer = intVal(security_item->arg); + if (implicit_item) + *implicit_cast = intVal(implicit_item->arg); +} + + /*------------- * Interpret the parameters *parameters and return their contents as * *byte_pct_p, etc. @@ -183,23 +281,14 @@ compute_parameter_types(List *argTypes, Oid languageOid, *------------ */ static void -compute_full_attributes(List *parameters, - int32 *byte_pct_p, int32 *perbyte_cpu_p, - int32 *percall_cpu_p, int32 *outin_ratio_p, - bool *isImplicit_p, bool *isStrict_p, - char *volatility_p) +compute_attributes_with_style(List *parameters, + int32 *byte_pct_p, int32 *perbyte_cpu_p, + int32 *percall_cpu_p, int32 *outin_ratio_p, + bool *isImplicit_p, bool *isStrict_p, + char *volatility_p) { List *pl; - /* the defaults */ - *byte_pct_p = BYTE_PCT; - *perbyte_cpu_p = PERBYTE_CPU; - *percall_cpu_p = PERCALL_CPU; - *outin_ratio_p = OUTIN_RATIO; - *isImplicit_p = false; - *isStrict_p = false; - *volatility_p = PROVOLATILE_VOLATILE; - foreach(pl, parameters) { DefElem *param = (DefElem *) lfirst(pl); @@ -290,12 +379,13 @@ interpret_AS_clause(Oid languageOid, const char *languageName, const List *as, * Execute a CREATE FUNCTION utility statement. */ void -CreateFunction(ProcedureStmt *stmt) +CreateFunction(CreateFunctionStmt *stmt) { char *probin_str; char *prosrc_str; Oid prorettype; bool returnsSet; + char *language; char languageName[NAMEDATALEN]; Oid languageOid; char *funcname; @@ -308,10 +398,12 @@ CreateFunction(ProcedureStmt *stmt) percall_cpu, outin_ratio; bool isImplicit, - isStrict; + isStrict, + security; char volatility; HeapTuple languageTuple; Form_pg_language languageStruct; + List *as_clause; /* Convert list of names to a name and namespace */ namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname, @@ -322,8 +414,21 @@ CreateFunction(ProcedureStmt *stmt) if (aclresult != ACLCHECK_OK) aclcheck_error(aclresult, get_namespace_name(namespaceId)); + /* defaults attributes */ + byte_pct = BYTE_PCT; + perbyte_cpu = PERBYTE_CPU; + percall_cpu = PERCALL_CPU; + outin_ratio = OUTIN_RATIO; + isImplicit = false; + isStrict = false; + volatility = PROVOLATILE_VOLATILE; + + /* override attributes from explicit list */ + compute_attributes_sql_style(stmt->options, + &as_clause, &language, &volatility, &isStrict, &security, &isImplicit); + /* Convert language name to canonical case */ - case_translate_language_name(stmt->language, languageName); + case_translate_language_name(language, languageName); /* Look up the language and validate permissions */ languageTuple = SearchSysCache(LANGNAME, @@ -363,12 +468,12 @@ CreateFunction(ProcedureStmt *stmt) parameterCount = compute_parameter_types(stmt->argTypes, languageOid, parameterTypes); - compute_full_attributes(stmt->withClause, - &byte_pct, &perbyte_cpu, &percall_cpu, - &outin_ratio, &isImplicit, &isStrict, - &volatility); + compute_attributes_with_style(stmt->withClause, + &byte_pct, &perbyte_cpu, &percall_cpu, + &outin_ratio, &isImplicit, &isStrict, + &volatility); - interpret_AS_clause(languageOid, languageName, stmt->as, + interpret_AS_clause(languageOid, languageName, as_clause, &prosrc_str, &probin_str); /* diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 909847dc856..1f0cc11934f 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.186 2002/05/17 01:19:17 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.187 2002/05/17 18:32:52 petere Exp $ * *------------------------------------------------------------------------- */ @@ -2098,18 +2098,17 @@ _copyIndexStmt(IndexStmt *from) return newnode; } -static ProcedureStmt * -_copyProcedureStmt(ProcedureStmt *from) +static CreateFunctionStmt * +_copyCreateFunctionStmt(CreateFunctionStmt *from) { - ProcedureStmt *newnode = makeNode(ProcedureStmt); + CreateFunctionStmt *newnode = makeNode(CreateFunctionStmt); newnode->replace = from->replace; Node_Copy(from, newnode, funcname); Node_Copy(from, newnode, argTypes); Node_Copy(from, newnode, returnType); + Node_Copy(from, newnode, options); Node_Copy(from, newnode, withClause); - Node_Copy(from, newnode, as); - newnode->language = pstrdup(from->language); return newnode; } @@ -2865,8 +2864,8 @@ copyObject(void *from) case T_IndexStmt: retval = _copyIndexStmt(from); break; - case T_ProcedureStmt: - retval = _copyProcedureStmt(from); + case T_CreateFunctionStmt: + retval = _copyCreateFunctionStmt(from); break; case T_RemoveAggrStmt: retval = _copyRemoveAggrStmt(from); diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c index 1f0d175326b..f48d6d033f4 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.133 2002/05/17 01:19:17 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.134 2002/05/17 18:32:52 petere Exp $ * *------------------------------------------------------------------------- */ @@ -923,7 +923,7 @@ _equalIndexStmt(IndexStmt *a, IndexStmt *b) } static bool -_equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b) +_equalCreateFunctionStmt(CreateFunctionStmt *a, CreateFunctionStmt *b) { if (a->replace != b->replace) return false; @@ -933,12 +933,10 @@ _equalProcedureStmt(ProcedureStmt *a, ProcedureStmt *b) return false; if (!equal(a->returnType, b->returnType)) return false; + if (!equal(a->options, b->options)) + return false; if (!equal(a->withClause, b->withClause)) return false; - if (!equal(a->as, b->as)) - return false; - if (!equalstr(a->language, b->language)) - return false; return true; } @@ -2020,8 +2018,8 @@ equal(void *a, void *b) case T_IndexStmt: retval = _equalIndexStmt(a, b); break; - case T_ProcedureStmt: - retval = _equalProcedureStmt(a, b); + case T_CreateFunctionStmt: + retval = _equalCreateFunctionStmt(a, b); break; case T_RemoveAggrStmt: retval = _equalRemoveAggrStmt(a, b); diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 0009b9df2f0..70a9e78cfa0 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.316 2002/05/17 01:19:17 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.317 2002/05/17 18:32:52 petere Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -141,7 +141,7 @@ static void doNegateFloat(Value *v); DropGroupStmt, DropPLangStmt, DropSchemaStmt, DropStmt, DropAssertStmt, DropTrigStmt, DropRuleStmt, DropUserStmt, DropdbStmt, ExplainStmt, FetchStmt, GrantStmt, IndexStmt, InsertStmt, ListenStmt, LoadStmt, LockStmt, - NotifyStmt, OptimizableStmt, ProcedureStmt, ReindexStmt, + NotifyStmt, OptimizableStmt, CreateFunctionStmt, ReindexStmt, RemoveAggrStmt, RemoveFuncStmt, RemoveOperStmt, RenameStmt, RevokeStmt, RuleActionStmt, RuleActionStmtOrEmpty, RuleStmt, SelectStmt, TransactionStmt, TruncateStmt, @@ -201,7 +201,7 @@ static void doNegateFloat(Value *v); %type stmtblock, stmtmulti, OptTableElementList, OptInherit, definition, opt_distinct, - opt_with, func_args, func_args_list, func_as, + opt_with, func_args, func_args_list, func_as, createfunc_opt_list oper_argtypes, RuleActionList, RuleActionMulti, opt_column_list, columnList, opt_name_list, sort_clause, sortby_list, index_params, index_list, name_list, @@ -214,6 +214,7 @@ static void doNegateFloat(Value *v); %type into_clause, OptTempTableName +%type createfunc_opt_item %type func_arg, func_return, func_type, aggr_argtype %type opt_arg, TriggerForOpt, TriggerForType, OptTemp, OptWithOids @@ -388,6 +389,9 @@ static void doNegateFloat(Value *v); TEMP, TEMPLATE, TOAST, TRUNCATE, TRUSTED, UNLISTEN, UNTIL, VACUUM, VALID, VERBOSE, VERSION +%token CALLED, DEFINER, EXTERNAL, IMMUTABLE, IMPLICIT, INPUT, + INVOKER, SECURITY, STABLE, STRICT, VOLATILE + /* The grammar thinks these are keywords, but they are not in the keywords.c * list and so can never be entered directly. The filter in parser.c * creates these tokens when required. @@ -467,6 +471,7 @@ stmt : AlterDatabaseSetStmt | CreateStmt | CreateAsStmt | CreateDomainStmt + | CreateFunctionStmt | CreateSchemaStmt | CreateGroupStmt | CreateSeqStmt @@ -494,7 +499,6 @@ stmt : AlterDatabaseSetStmt | UnlistenStmt | LockStmt | NotifyStmt - | ProcedureStmt | ReindexStmt | RemoveAggrStmt | RemoveOperStmt @@ -2769,17 +2773,16 @@ RecipeStmt: EXECUTE RECIPE recipe_name * *****************************************************************************/ -ProcedureStmt: CREATE opt_or_replace FUNCTION func_name func_args - RETURNS func_return AS func_as LANGUAGE ColId_or_Sconst opt_with +CreateFunctionStmt: CREATE opt_or_replace FUNCTION func_name func_args + RETURNS func_return createfunc_opt_list opt_with { - ProcedureStmt *n = makeNode(ProcedureStmt); + CreateFunctionStmt *n = makeNode(CreateFunctionStmt); n->replace = $2; n->funcname = $4; n->argTypes = $5; n->returnType = $7; - n->withClause = $12; - n->as = $9; - n->language = $11; + n->options = $8; + n->withClause = $9; $$ = (Node *)n; }; @@ -2787,10 +2790,6 @@ opt_or_replace: OR REPLACE { $$ = TRUE; } | /*EMPTY*/ { $$ = FALSE; } ; -opt_with: WITH definition { $$ = $2; } - | /*EMPTY*/ { $$ = NIL; } - ; - func_args: '(' func_args_list ')' { $$ = $2; } | '(' ')' { $$ = NIL; } ; @@ -2831,12 +2830,6 @@ opt_arg: IN } ; -func_as: Sconst - { $$ = makeList1(makeString($1)); } - | Sconst ',' Sconst - { $$ = makeList2(makeString($1), makeString($3)); } - ; - func_return: func_type { /* We can catch over-specified arguments here if we want to, @@ -2864,6 +2857,104 @@ func_type: Typename } ; + +createfunc_opt_list: createfunc_opt_item + { $$ = makeList1($1); } + | createfunc_opt_list createfunc_opt_item + { $$ = lappend($1, $2); } + ; + +createfunc_opt_item: AS func_as + { + $$ = makeNode(DefElem); + $$->defname = "as"; + $$->arg = (Node *)$2; + } + | LANGUAGE ColId_or_Sconst + { + $$ = makeNode(DefElem); + $$->defname = "language"; + $$->arg = (Node *)makeString($2); + } + | IMMUTABLE + { + $$ = makeNode(DefElem); + $$->defname = "volatility"; + $$->arg = (Node *)makeString("immutable"); + } + | STABLE + { + $$ = makeNode(DefElem); + $$->defname = "volatility"; + $$->arg = (Node *)makeString("stable"); + } + | VOLATILE + { + $$ = makeNode(DefElem); + $$->defname = "volatility"; + $$->arg = (Node *)makeString("volatile"); + } + | CALLED ON NULL_P INPUT + { + $$ = makeNode(DefElem); + $$->defname = "strict"; + $$->arg = (Node *)makeInteger(FALSE); + } + | RETURNS NULL_P ON NULL_P INPUT + { + $$ = makeNode(DefElem); + $$->defname = "strict"; + $$->arg = (Node *)makeInteger(TRUE); + } + | STRICT + { + $$ = makeNode(DefElem); + $$->defname = "strict"; + $$->arg = (Node *)makeInteger(TRUE); + } + | EXTERNAL SECURITY DEFINER + { + $$ = makeNode(DefElem); + $$->defname = "security"; + $$->arg = (Node *)makeInteger(TRUE); + } + | EXTERNAL SECURITY INVOKER + { + $$ = makeNode(DefElem); + $$->defname = "security"; + $$->arg = (Node *)makeInteger(FALSE); + } + | SECURITY DEFINER + { + $$ = makeNode(DefElem); + $$->defname = "security"; + $$->arg = (Node *)makeInteger(TRUE); + } + | SECURITY INVOKER + { + $$ = makeNode(DefElem); + $$->defname = "security"; + $$->arg = (Node *)makeInteger(FALSE); + } + | IMPLICIT CAST + { + $$ = makeNode(DefElem); + $$->defname = "implicit"; + $$->arg = (Node *)makeInteger(TRUE); + } + ; + +func_as: Sconst + { $$ = makeList1(makeString($1)); } + | Sconst ',' Sconst + { $$ = makeList2(makeString($1), makeString($3)); } + ; + +opt_with: WITH definition { $$ = $2; } + | /*EMPTY*/ { $$ = NIL; } + ; + + /***************************************************************************** * * QUERY: @@ -6137,6 +6228,7 @@ unreserved_keyword: | BEGIN_TRANS | BY | CACHE + | CALLED | CASCADE | CHAIN | CHARACTERISTICS @@ -6156,6 +6248,7 @@ unreserved_keyword: | DAY_P | DECLARE | DEFERRED + | DEFINER | DELETE | DELIMITERS | DOMAIN_P @@ -6168,6 +6261,7 @@ unreserved_keyword: | EXCLUSIVE | EXECUTE | EXPLAIN + | EXTERNAL | FETCH | FORCE | FORWARD @@ -6176,13 +6270,17 @@ unreserved_keyword: | HANDLER | HOUR_P | IMMEDIATE + | IMMUTABLE + | IMPLICIT | INCREMENT | INDEX | INHERITS | INOUT + | INPUT | INSENSITIVE | INSERT | INSTEAD + | INVOKER | ISOLATION | KEY | LANGUAGE @@ -6238,18 +6336,21 @@ unreserved_keyword: | SCHEMA | SCROLL | SECOND_P + | SECURITY | SESSION | SEQUENCE | SERIALIZABLE | SET | SHARE | SHOW + | STABLE | START | STATEMENT | STATISTICS | STDIN | STDOUT | STORAGE + | STRICT | SYSID | TEMP | TEMPLATE @@ -6272,6 +6373,7 @@ unreserved_keyword: | VARYING | VERSION | VIEW + | VOLATILE | WITH | WITHOUT | WORK diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 0c7612350a5..36900127ea8 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.109 2002/05/03 00:32:16 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.110 2002/05/17 18:32:52 petere Exp $ * *------------------------------------------------------------------------- */ @@ -57,6 +57,7 @@ static const ScanKeyword ScanKeywords[] = { {"both", BOTH}, {"by", BY}, {"cache", CACHE}, + {"called", CALLED}, {"cascade", CASCADE}, {"case", CASE}, {"cast", CAST}, @@ -95,6 +96,7 @@ static const ScanKeyword ScanKeywords[] = { {"default", DEFAULT}, {"deferrable", DEFERRABLE}, {"deferred", DEFERRED}, + {"definer", DEFINER}, {"delete", DELETE}, {"delimiters", DELIMITERS}, {"desc", DESC}, @@ -114,6 +116,7 @@ static const ScanKeyword ScanKeywords[] = { {"execute", EXECUTE}, {"exists", EXISTS}, {"explain", EXPLAIN}, + {"external", EXTERNAL}, {"extract", EXTRACT}, {"false", FALSE_P}, {"fetch", FETCH}, @@ -134,6 +137,8 @@ static const ScanKeyword ScanKeywords[] = { {"hour", HOUR_P}, {"ilike", ILIKE}, {"immediate", IMMEDIATE}, + {"immutable", IMMUTABLE}, + {"implicit", IMPLICIT}, {"in", IN}, {"increment", INCREMENT}, {"index", INDEX}, @@ -141,6 +146,7 @@ static const ScanKeyword ScanKeywords[] = { {"initially", INITIALLY}, {"inner", INNER_P}, {"inout", INOUT}, + {"input", INPUT}, {"insensitive", INSENSITIVE}, {"insert", INSERT}, {"instead", INSTEAD}, @@ -149,6 +155,7 @@ static const ScanKeyword ScanKeywords[] = { {"intersect", INTERSECT}, {"interval", INTERVAL}, {"into", INTO}, + {"invoker", INVOKER}, {"is", IS}, {"isnull", ISNULL}, {"isolation", ISOLATION}, @@ -234,6 +241,7 @@ static const ScanKeyword ScanKeywords[] = { {"schema", SCHEMA}, {"scroll", SCROLL}, {"second", SECOND_P}, + {"security", SECURITY}, {"select", SELECT}, {"sequence", SEQUENCE}, {"serializable", SERIALIZABLE}, @@ -245,12 +253,14 @@ static const ScanKeyword ScanKeywords[] = { {"show", SHOW}, {"smallint", SMALLINT}, {"some", SOME}, + {"stable", STABLE}, {"start", START}, {"statement", STATEMENT}, {"statistics", STATISTICS}, {"stdin", STDIN}, {"stdout", STDOUT}, {"storage", STORAGE}, + {"strict", STRICT}, {"substring", SUBSTRING}, {"sysid", SYSID}, {"table", TABLE}, @@ -288,6 +298,7 @@ static const ScanKeyword ScanKeywords[] = { {"verbose", VERBOSE}, {"version", VERSION}, {"view", VIEW}, + {"volatile", VOLATILE}, {"when", WHEN}, {"where", WHERE}, {"with", WITH}, diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 53bf45dce9c..1ea4fa9a6b5 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.265 2002/05/17 01:19:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.266 2002/05/17 18:32:52 petere Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -1688,7 +1688,7 @@ PostgresMain(int argc, char *argv[], const char *username) if (!IsUnderPostmaster) { puts("\nPOSTGRES backend interactive interface "); - puts("$Revision: 1.265 $ $Date: 2002/05/17 01:19:18 $\n"); + puts("$Revision: 1.266 $ $Date: 2002/05/17 18:32:52 $\n"); } /* @@ -2229,7 +2229,7 @@ CreateCommandTag(Node *parsetree) tag = "CREATE"; break; - case T_ProcedureStmt: /* CREATE FUNCTION */ + case T_CreateFunctionStmt: /* CREATE FUNCTION */ tag = "CREATE"; break; diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c index e72d8dfccf7..e7091d9aa34 100644 --- a/src/backend/tcop/utility.c +++ b/src/backend/tcop/utility.c @@ -10,7 +10,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.154 2002/05/17 01:19:18 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.155 2002/05/17 18:32:52 petere Exp $ * *------------------------------------------------------------------------- */ @@ -574,8 +574,8 @@ ProcessUtility(Node *parsetree, } break; - case T_ProcedureStmt: /* CREATE FUNCTION */ - CreateFunction((ProcedureStmt *) parsetree); + case T_CreateFunctionStmt: /* CREATE FUNCTION */ + CreateFunction((CreateFunctionStmt *) parsetree); break; case T_IndexStmt: /* CREATE INDEX */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index f3b8f8a19b1..cb268c50bf1 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.260 2002/05/13 17:45:30 tgl Exp $ + * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.261 2002/05/17 18:32:52 petere Exp $ * *------------------------------------------------------------------------- */ @@ -3152,18 +3152,14 @@ dumpProcLangs(Archive *fout, FuncInfo *finfo, int numFuncs) (*deps)[depIdx++] = strdup(lanplcallfoid); - appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE "); - formatStringLiteral(delqry, lanname, CONV_ALL); - appendPQExpBuffer(delqry, ";\n"); + appendPQExpBuffer(delqry, "DROP PROCEDURAL LANGUAGE %s;\n", fmtId(lanname, force_quotes)); - appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE ", + appendPQExpBuffer(defqry, "CREATE %sPROCEDURAL LANGUAGE %s", (PQgetvalue(res, i, i_lanpltrusted)[0] == 't') ? - "TRUSTED " : ""); - formatStringLiteral(defqry, lanname, CONV_ALL); - appendPQExpBuffer(defqry, " HANDLER %s LANCOMPILER ", + "TRUSTED " : "", + fmtId(lanname, force_quotes)); + appendPQExpBuffer(defqry, " HANDLER %s;\n", fmtId(finfo[fidx].proname, force_quotes)); - formatStringLiteral(defqry, lancompiler, CONV_ALL); - appendPQExpBuffer(defqry, ";\n"); (*deps)[depIdx++] = NULL; /* End of List */ @@ -3221,9 +3217,6 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo) char *proimplicit; char *proisstrict; char *lanname; - char *listSep; - char *listSepComma = ","; - char *listSepNone = ""; char *rettypename; if (finfo->dumped) @@ -3337,52 +3330,33 @@ dumpOneFunc(Archive *fout, FuncInfo *finfo) rettypename = getFormattedTypeName(finfo->prorettype, zeroAsOpaque); appendPQExpBuffer(q, "CREATE FUNCTION %s ", fn->data); - appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE ", + appendPQExpBuffer(q, "RETURNS %s%s %s LANGUAGE %s", (proretset[0] == 't') ? "SETOF " : "", rettypename, - asPart->data); - formatStringLiteral(q, lanname, CONV_ALL); + asPart->data, + fmtId(lanname, force_quotes)); free(rettypename); - if (provolatile[0] != PROVOLATILE_VOLATILE || - proimplicit[0] == 't' || - proisstrict[0] == 't') /* OR in new attrs here */ + if (provolatile[0] != PROVOLATILE_VOLATILE) { - appendPQExpBuffer(q, " WITH ("); - listSep = listSepNone; - if (provolatile[0] == PROVOLATILE_IMMUTABLE) - { - appendPQExpBuffer(q, "%s isImmutable", listSep); - listSep = listSepComma; - } + appendPQExpBuffer(q, " IMMUTABLE"); else if (provolatile[0] == PROVOLATILE_STABLE) - { - appendPQExpBuffer(q, "%s isStable", listSep); - listSep = listSepComma; - } + appendPQExpBuffer(q, " STABLE"); else if (provolatile[0] != PROVOLATILE_VOLATILE) { write_msg(NULL, "Unexpected provolatile value for function %s\n", finfo->proname); exit_nicely(); } + } - if (proimplicit[0] == 't') - { - appendPQExpBuffer(q, "%s implicitCoercion", listSep); - listSep = listSepComma; - } + if (proimplicit[0] == 't') + appendPQExpBuffer(q, " IMPLICIT CAST"); - if (proisstrict[0] == 't') - { - appendPQExpBuffer(q, "%s isStrict", listSep); - listSep = listSepComma; - } - - appendPQExpBuffer(q, " )"); - } + if (proisstrict[0] == 't') + appendPQExpBuffer(q, " STRICT"); appendPQExpBuffer(q, ";\n"); diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 4e257fbd91a..cf9048c714b 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.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: defrem.h,v 1.36 2002/04/16 23:08:12 tgl Exp $ + * $Id: defrem.h,v 1.37 2002/05/17 18:32:52 petere Exp $ * *------------------------------------------------------------------------- */ @@ -38,7 +38,7 @@ extern void ReindexDatabase(const char *databaseName, bool force, bool all); * DefineFoo and RemoveFoo are now both in foocmds.c */ -extern void CreateFunction(ProcedureStmt *stmt); +extern void CreateFunction(CreateFunctionStmt *stmt); extern void RemoveFunction(List *functionName, List *argTypes); extern void DefineOperator(List *names, List *parameters); diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h index 7de647d1362..6aa253e9d41 100644 --- a/src/include/nodes/nodes.h +++ b/src/include/nodes/nodes.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: nodes.h,v 1.107 2002/05/12 23:43:04 tgl Exp $ + * $Id: nodes.h,v 1.108 2002/05/17 18:32:52 petere Exp $ * *------------------------------------------------------------------------- */ @@ -160,7 +160,7 @@ typedef enum NodeTag T_CommentStmt, T_FetchStmt, T_IndexStmt, - T_ProcedureStmt, + T_CreateFunctionStmt, T_RemoveAggrStmt, T_RemoveFuncStmt, T_RemoveOperStmt, diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index a0bf47d7ed0..3466e125982 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.177 2002/05/17 01:19:19 tgl Exp $ + * $Id: parsenodes.h,v 1.178 2002/05/17 18:32:52 petere Exp $ * *------------------------------------------------------------------------- */ @@ -1200,17 +1200,16 @@ typedef struct IndexStmt * Create Function Statement * ---------------------- */ -typedef struct ProcedureStmt +typedef struct CreateFunctionStmt { NodeTag type; bool replace; /* T => replace if already exists */ List *funcname; /* qualified name of function to create */ List *argTypes; /* list of argument types (TypeName nodes) */ TypeName *returnType; /* the return type */ + List *options; /* a list of DefElem */ List *withClause; /* a list of DefElem */ - List *as; /* definition of function body */ - char *language; /* C, SQL, etc */ -} ProcedureStmt; +} CreateFunctionStmt; /* ---------------------- * Drop Aggregate Statement