{"Entry":{"collection":"sql","key":"create-function","name":"CREATE FUNCTION","aliases":["createfunction"],"metadata":{"aliases":["createfunction"],"changed_in":["6.5","7.0","7.1","7.2","7.3","8.0","8.1","8.3","8.4","9.0","9.2","9.5","9.6","11","12","14"],"changes":[{"from":"6.4","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","usage","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":["AS definition"],"removed":["AS path"]},"to":"6.5"},{"from":"6.5","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","usage","compatibility"],"removed":["bugs"]},"status":"changed","synopsis":{"added":["[ WITH ( attribute [, ...] ) ]","CREATE FUNCTION name ( [ ftype [, ...] ] )","RETURNS rtype","AS obj_file , link_symbol","LANGUAGE 'C'","[ WITH ( attribute [, ...] ) ]"],"removed":[]},"to":"7.0"},{"from":"7.0","purpose_changed":false,"renamed":{"from_file":"sql-createfunction.htm","to_file":"sql-createfunction.html"},"sections":{"added":[],"changed":["description","usage","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":["LANGUAGE 'langname'"],"removed":["LANGUAGE 'C'"]},"to":"7.1"},{"from":"7.1","purpose_changed":true,"renamed":null,"sections":{"added":["notes","examples","see_also"],"changed":["description","compatibility"],"removed":["usage"]},"status":"changed","synopsis":{"added":["CREATE [ OR REPLACE ] FUNCTION name ( [ argtype [, ...] ] )","RETURNS rettype","AS 'definition'","LANGUAGE langname","CREATE [ OR REPLACE ] FUNCTION name ( [ argtype [, ...] ] )","RETURNS rettype","AS 'obj_file', 'link_symbol'","LANGUAGE langname"],"removed":["CREATE FUNCTION name ( [ ftype [, ...] ] )","RETURNS rtype","AS definition","LANGUAGE 'langname'","CREATE FUNCTION name ( [ ftype [, ...] ] )","RETURNS rtype","AS obj_file , link_symbol","LANGUAGE 'langname'"]},"to":"7.2"},{"from":"7.2","purpose_changed":false,"renamed":null,"sections":{"added":["other"],"changed":["description","notes","examples","compatibility","see_also"],"removed":[]},"status":"changed","synopsis":{"added":["{ LANGUAGE langname","| IMMUTABLE | STABLE | VOLATILE","| CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT","| [EXTERNAL] SECURITY INVOKER | [EXTERNAL] SECURITY DEFINER","| AS 'definition'","| AS 'obj_file', 'link_symbol'","} ..."],"removed":["LANGUAGE langname","CREATE [ OR REPLACE ] FUNCTION name ( [ argtype [, ...] ] )","RETURNS rettype","AS 'obj_file', 'link_symbol'","LANGUAGE langname","[ WITH ( attribute [, ...] ) ]"]},"to":"7.3"},{"from":"7.3","purpose_changed":false,"renamed":null,"sections":{"added":["parameters"],"changed":["description","notes","examples","see_also"],"removed":[]},"status":"changed","synopsis":null,"to":"7.4"},{"from":"7.4","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes","examples","other","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":["CREATE [ OR REPLACE ] FUNCTION name ( [ [ argname ] argtype [, ...] ] )"],"removed":[]},"to":"8.0"},{"from":"8.0","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes","examples","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":["name ( [ [ argmode ] [ argname ] argtype [, ...] ] )","[ RETURNS rettype ]"],"removed":[]},"to":"8.1"},{"from":"8.1","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters","notes","examples"],"removed":[]},"status":"changed","synopsis":null,"to":"8.2"},{"from":"8.2","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes","examples","other"],"removed":[]},"status":"changed","synopsis":{"added":["| COST execution_cost","| ROWS result_rows","| SET configuration_parameter { TO value | = value | FROM CURRENT }","| AS 'definition'"],"removed":[]},"to":"8.3"},{"from":"8.3","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","notes","examples","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":["name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } defexpr ] [, ...] ] )","| RETURNS TABLE ( colname coltype [, ...] ) ]","| WINDOW"],"removed":[]},"to":"8.4"},{"from":"8.4","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","other","notes","examples"],"removed":[]},"status":"changed","synopsis":{"added":["name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )","| RETURNS TABLE ( column_name column_type [, ...] ) ]","{ LANGUAGE lang_name"],"removed":["name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } defexpr ] [, ...] ] )","| RETURNS TABLE ( colname coltype [, ...] ) ]","{ LANGUAGE langname"]},"to":"9.0"},{"from":"9.0","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters"],"removed":[]},"status":"changed","synopsis":null,"to":"9.1"},{"from":"9.1","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters"],"removed":[]},"status":"changed","synopsis":{"added":["| IMMUTABLE | STABLE | VOLATILE | [ NOT ] LEAKPROOF"],"removed":[]},"to":"9.2"},{"from":"9.2","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters","other","compatibility"],"removed":[]},"status":"changed","synopsis":null,"to":"9.3"},{"from":"9.3","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters"],"removed":[]},"status":"changed","synopsis":null,"to":"9.4"},{"from":"9.4","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters"],"removed":[]},"status":"changed","synopsis":{"added":["| TRANSFORM { FOR TYPE type_name } [, ... ]"],"removed":[]},"to":"9.5"},{"from":"9.5","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters","other","examples"],"removed":[]},"status":"changed","synopsis":{"added":["| { IMMUTABLE | STABLE | VOLATILE }","| { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }","| { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }","| PARALLEL { UNSAFE | RESTRICTED | SAFE }"],"removed":[]},"to":"9.6"},{"from":"9.6","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters","other","examples","see_also"],"removed":[]},"status":"changed","synopsis":null,"to":"10"},{"from":"10","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","examples","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":[],"removed":["[ WITH ( attribute [, ...] ) ]"]},"to":"11"},{"from":"11","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","other"],"removed":[]},"status":"changed","synopsis":{"added":["| SUPPORT support_function","| SET configuration_parameter { TO value | = value | FROM CURRENT }"],"removed":[]},"to":"12"},{"from":"13","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","examples","compatibility"],"removed":[]},"status":"changed","synopsis":{"added":["| sql_body"],"removed":[]},"to":"14"},{"from":"15","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["parameters","other"],"removed":[]},"status":"changed","synopsis":null,"to":"16"},{"from":"16","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["description","parameters","other"],"removed":[]},"status":"changed","synopsis":null,"to":"17"},{"from":"18","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["other","examples"],"removed":[]},"status":"changed","synopsis":null,"to":"19"},{"from":"19","purpose_changed":false,"renamed":null,"sections":{"added":[],"changed":["see_also"],"removed":[]},"status":"changed","synopsis":null,"to":"20"}],"content_hash":"5fd10f2dc7f7539b68fdb5fa1f18f12b741a651e3f26dfcab456a0b2942e34a4","editorial":{},"first_version":"6.4","group":"routine","imported_at":"2026-09-30T17:43:37.11648+08:00","last_version":"20","name":"CREATE FUNCTION","object":"FUNCTION","position":2005,"present_in":["6.4","6.5","7.0","7.1","7.2","7.3","7.4","8.0","8.1","8.2","8.3","8.4","9.0","9.1","9.2","9.3","9.4","9.5","9.6","10","11","12","13","14","15","16","17","18","19","20"],"purpose":"define a new function","purpose_zh":"","related":["alter-function","create-procedure","drop-function","grant","load","revoke"],"slug":"create-function","source_rev":"a709ab85","synopsis":"CREATE [ OR REPLACE ] FUNCTION\nname ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )\n[ RETURNS rettype\n| RETURNS TABLE ( column_name column_type [, ...] ) ]\n{ LANGUAGE lang_name\n| TRANSFORM { FOR TYPE type_name } [, ... ]\n| WINDOW\n| { IMMUTABLE | STABLE | VOLATILE }\n| [ NOT ] LEAKPROOF\n| { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }\n| { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }\n| PARALLEL { UNSAFE | RESTRICTED | SAFE }\n| COST execution_cost\n| ROWS result_rows\n| SUPPORT support_function\n| SET configuration_parameter { TO value | = value | FROM CURRENT }\n| AS 'definition'\n| AS 'obj_file', 'link_symbol'\n| sql_body\n} ...","verb":"CREATE"}},"Definition":{"Collection":"sql","Key":"create-function","SourceDatabase":"center","Version":"18","SourceTable":"sqlcmd","SourceKey":"create-function","SourceRevision":"a709ab85","Facts":{"anchor":"SQL-CREATEFUNCTION","file":"sql-createfunction.html","lang":"en","name":"CREATE FUNCTION","purpose":"define a new function","purpose_zh":"","related":["alter-function","drop-function","grant","load","revoke"],"sections":[{"html":"\u003cp\u003e\u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e defines a new function. \u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e will either create a new function, or replace an existing definition. To be able to define a function, the user must have the \u003ccode class=\"literal\"\u003eUSAGE\u003c/code\u003e privilege on the language.\u003c/p\u003e\u003cp\u003eIf a schema name is included, then the function is created in the specified schema. Otherwise it is created in the current schema. The name of the new function must not match any existing function or procedure with the same input argument types in the same schema. However, functions and procedures of different argument types can share a name (this is called \u003cem class=\"firstterm\"\u003eoverloading\u003c/em\u003e).\u003c/p\u003e\u003cp\u003eTo replace the current definition of an existing function, use \u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e. It is not possible to change the name or argument types of a function this way (if you tried, you would actually be creating a new, distinct function). Also, \u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e will not let you change the return type of an existing function. To do that, you must drop and recreate the function. (When using \u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e parameters, that means you cannot change the types of any \u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e parameters except by dropping the function.)\u003c/p\u003e\u003cp\u003eWhen \u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e is used to replace an existing function, the ownership and permissions of the function do not change. All other function properties are assigned the values specified or implied in the command. You must own the function to replace it (this includes being a member of the owning role).\u003c/p\u003e\u003cp\u003eIf you drop and then recreate a function, the new function is not the same entity as the old; you will have to drop existing rules, views, triggers, etc. that refer to the old function. Use \u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e to change a function definition without breaking objects that refer to the function. Also, \u003ccode class=\"command\"\u003eALTER FUNCTION\u003c/code\u003e can be used to change most of the auxiliary properties of an existing function.\u003c/p\u003e\u003cp\u003eThe user that creates the function becomes the owner of the function.\u003c/p\u003e\u003cp\u003eTo be able to create a function, you must have \u003ccode class=\"literal\"\u003eUSAGE\u003c/code\u003e privilege on the argument types and the return type.\u003c/p\u003e\u003cp\u003eRefer to \u003ca href=\"/docs/18/xfunc.html\" title=\"36.3. User-Defined Functions\"\u003eSection 36.3\u003c/a\u003e for further information on writing functions.\u003c/p\u003e","key":"description","title":"Description"},{"html":"\u003cdiv class=\"variablelist\"\u003e\u003cdl class=\"variablelist\"\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name (optionally schema-qualified) of the function to create.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eargmode\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe mode of an argument: \u003ccode class=\"literal\"\u003eIN\u003c/code\u003e, \u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e, \u003ccode class=\"literal\"\u003eINOUT\u003c/code\u003e, or \u003ccode class=\"literal\"\u003eVARIADIC\u003c/code\u003e. If omitted, the default is \u003ccode class=\"literal\"\u003eIN\u003c/code\u003e. Only \u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e arguments can follow a \u003ccode class=\"literal\"\u003eVARIADIC\u003c/code\u003e one. Also, \u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e and \u003ccode class=\"literal\"\u003eINOUT\u003c/code\u003e arguments cannot be used together with the \u003ccode class=\"literal\"\u003eRETURNS TABLE\u003c/code\u003e notation.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eargname\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of an argument. Some languages (including SQL and PL/pgSQL) let you use the name in the function body. For other languages the name of an input argument is just extra documentation, so far as the function itself is concerned; but you can use input argument names when calling a function to improve readability (see \u003ca href=\"/docs/18/sql-syntax-calling-funcs.html\" title=\"4.3. Calling Functions\"\u003eSection 4.3\u003c/a\u003e). In any case, the name of an output argument is significant, because it defines the column name in the result row type. (If you omit the name for an output argument, the system will choose a default column name.)\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eargtype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe data type(s) of the function's arguments (optionally schema-qualified), if any. The argument types can be base, composite, or domain types, or can reference the type of a table column.\u003c/p\u003e\u003cp\u003eDepending on the implementation language it might also be allowed to specify \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003epseudo-types\u003c/span\u003e”\u003c/span\u003e such as \u003ccode class=\"type\"\u003ecstring\u003c/code\u003e. Pseudo-types indicate that the actual argument type is either incompletely specified, or outside the set of ordinary SQL data types.\u003c/p\u003e\u003cp\u003eThe type of a column is referenced by writing \u003ccode class=\"literal\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003etable_name\u003c/code\u003e\u003c/em\u003e.\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e%TYPE\u003c/code\u003e. Using this feature can sometimes help make a function independent of changes to the definition of a table.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefault_expr\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eAn expression to be used as default value if the parameter is not specified. The expression has to be coercible to the argument type of the parameter. Only input (including \u003ccode class=\"literal\"\u003eINOUT\u003c/code\u003e) parameters can have a default value. All input parameters following a parameter with a default value must have default values as well.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003erettype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe return data type (optionally schema-qualified). The return type can be a base, composite, or domain type, or can reference the type of a table column. Depending on the implementation language it might also be allowed to specify \u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003epseudo-types\u003c/span\u003e”\u003c/span\u003e such as \u003ccode class=\"type\"\u003ecstring\u003c/code\u003e. If the function is not supposed to return a value, specify \u003ccode class=\"type\"\u003evoid\u003c/code\u003e as the return type.\u003c/p\u003e\u003cp\u003eWhen there are \u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e or \u003ccode class=\"literal\"\u003eINOUT\u003c/code\u003e parameters, the \u003ccode class=\"literal\"\u003eRETURNS\u003c/code\u003e clause can be omitted. If present, it must agree with the result type implied by the output parameters: \u003ccode class=\"literal\"\u003eRECORD\u003c/code\u003e if there are multiple output parameters, or the same type as the single output parameter.\u003c/p\u003e\u003cp\u003eThe \u003ccode class=\"literal\"\u003eSETOF\u003c/code\u003e modifier indicates that the function will return a set of items, rather than a single item.\u003c/p\u003e\u003cp\u003eThe type of a column is referenced by writing \u003ccode class=\"literal\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003etable_name\u003c/code\u003e\u003c/em\u003e.\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e%TYPE\u003c/code\u003e.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of an output column in the \u003ccode class=\"literal\"\u003eRETURNS TABLE\u003c/code\u003e syntax. This is effectively another way of declaring a named \u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e parameter, except that \u003ccode class=\"literal\"\u003eRETURNS TABLE\u003c/code\u003e also implies \u003ccode class=\"literal\"\u003eRETURNS SETOF\u003c/code\u003e.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe data type of an output column in the \u003ccode class=\"literal\"\u003eRETURNS TABLE\u003c/code\u003e syntax.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003elang_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name of the language that the function is implemented in. It can be \u003ccode class=\"literal\"\u003esql\u003c/code\u003e, \u003ccode class=\"literal\"\u003ec\u003c/code\u003e, \u003ccode class=\"literal\"\u003einternal\u003c/code\u003e, or the name of a user-defined procedural language, e.g., \u003ccode class=\"literal\"\u003eplpgsql\u003c/code\u003e. The default is \u003ccode class=\"literal\"\u003esql\u003c/code\u003e if \u003cem class=\"replaceable\"\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e is specified. Enclosing the name in single quotes is deprecated and requires matching case.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eTRANSFORM { FOR TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_name\u003c/code\u003e\u003c/em\u003e } [, ... ] }\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eLists which transforms a call to the function should apply. Transforms convert between SQL types and language-specific data types; see \u003ca href=\"/docs/18/sql-createtransform.html\" title=\"CREATE TRANSFORM\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE TRANSFORM\u003c/span\u003e\u003c/a\u003e. Procedural language implementations usually have hardcoded knowledge of the built-in types, so those don't need to be listed here. If a procedural language implementation does not know how to handle a type and no transform is supplied, it will fall back to a default behavior for converting data types, but this depends on the implementation.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eWINDOW\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eWINDOW\u003c/code\u003e indicates that the function is a \u003cem class=\"firstterm\"\u003ewindow function\u003c/em\u003e rather than a plain function. This is currently only useful for functions written in C. The \u003ccode class=\"literal\"\u003eWINDOW\u003c/code\u003e attribute cannot be changed when replacing an existing function definition.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eIMMUTABLE\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eSTABLE\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eVOLATILE\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThese attributes inform the query optimizer about the behavior of the function. At most one choice can be specified. If none of these appear, \u003ccode class=\"literal\"\u003eVOLATILE\u003c/code\u003e is the default assumption.\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eIMMUTABLE\u003c/code\u003e indicates that the function cannot modify the database and 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 argument list. If this option is given, any call of the function with all-constant arguments can be immediately replaced with the function value.\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eSTABLE\u003c/code\u003e indicates that the function cannot modify the database, and that within a single table scan it 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. (It is inappropriate for \u003ccode class=\"literal\"\u003eAFTER\u003c/code\u003e triggers that wish to query rows modified by the current command.) Also note that the \u003ccode class=\"function\"\u003ecurrent_timestamp\u003c/code\u003e family of functions qualify as stable, since their values do not change within a transaction.\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eVOLATILE\u003c/code\u003e 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 \u003ccode class=\"literal\"\u003erandom()\u003c/code\u003e, \u003ccode class=\"literal\"\u003ecurrval()\u003c/code\u003e, \u003ccode class=\"literal\"\u003etimeofday()\u003c/code\u003e. But 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 \u003ccode class=\"literal\"\u003esetval()\u003c/code\u003e.\u003c/p\u003e\u003cp\u003eFor additional details see \u003ca href=\"/docs/18/xfunc-volatility.html\" title=\"36.7. Function Volatility Categories\"\u003eSection 36.7\u003c/a\u003e.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eLEAKPROOF\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eLEAKPROOF\u003c/code\u003e indicates that the function has no side effects. It reveals no information about its arguments other than by its return value. For example, a function which throws an error message for some argument values but not others, or which includes the argument values in any error message, is not leakproof. This affects how the system executes queries against views created with the \u003ccode class=\"literal\"\u003esecurity_barrier\u003c/code\u003e option or tables with row level security enabled. The system will enforce conditions from security policies and security barrier views before any user-supplied conditions from the query itself that contain non-leakproof functions, in order to prevent the inadvertent exposure of data. Functions and operators marked as leakproof are assumed to be trustworthy, and may be executed before conditions from security policies and security barrier views. In addition, functions which do not take arguments or which are not passed any arguments from the security barrier view or table do not have to be marked as leakproof to be executed before security conditions. See \u003ca href=\"/docs/18/sql-createview.html\" title=\"CREATE VIEW\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE VIEW\u003c/span\u003e\u003c/a\u003e and \u003ca href=\"/docs/18/rules-privileges.html\" title=\"39.5. Rules and Privileges\"\u003eSection 39.5\u003c/a\u003e. This option can only be set by the superuser.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eCALLED ON NULL INPUT\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eSTRICT\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eCALLED ON NULL INPUT\u003c/code\u003e (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 null values if necessary and respond appropriately.\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e or \u003ccode class=\"literal\"\u003eSTRICT\u003c/code\u003e 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.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003e[\u003cspan class=\"optional\"\u003eEXTERNAL\u003c/span\u003e] SECURITY INVOKER\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003e[\u003cspan class=\"optional\"\u003eEXTERNAL\u003c/span\u003e] SECURITY DEFINER\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eSECURITY INVOKER\u003c/code\u003e indicates that the function is to be executed with the privileges of the user that calls it. That is the default. \u003ccode class=\"literal\"\u003eSECURITY DEFINER\u003c/code\u003e specifies that the function is to be executed with the privileges of the user that owns it. For information on how to write \u003ccode class=\"literal\"\u003eSECURITY DEFINER\u003c/code\u003e functions safely, \u003ca href=\"/docs/18/sql-createfunction.html#SQL-CREATEFUNCTION-SECURITY\" title=\"Writing SECURITY DEFINER Functions Safely\"\u003esee below\u003c/a\u003e.\u003c/p\u003e\u003cp\u003eThe key word \u003ccode class=\"literal\"\u003eEXTERNAL\u003c/code\u003e is allowed for SQL conformance, but it is optional since, unlike in SQL, this feature applies to all functions not only external ones.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003ePARALLEL\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003ePARALLEL UNSAFE\u003c/code\u003e indicates that the function can't be executed in parallel mode; the presence of such a function in an SQL statement forces a serial execution plan. This is the default. \u003ccode class=\"literal\"\u003ePARALLEL RESTRICTED\u003c/code\u003e indicates that the function can be executed in parallel mode, but only in the parallel group leader process. \u003ccode class=\"literal\"\u003ePARALLEL SAFE\u003c/code\u003e indicates that the function is safe to run in parallel mode without restriction, including in parallel worker processes.\u003c/p\u003e\u003cp\u003eFunctions should be labeled parallel unsafe if they modify any database state, change the transaction state (other than by using a subtransaction for error recovery), access sequences (e.g., by calling \u003ccode class=\"literal\"\u003ecurrval\u003c/code\u003e) or make persistent changes to settings. They should be labeled parallel restricted if they access temporary tables, client connection state, cursors, prepared statements, or miscellaneous backend-local state which the system cannot synchronize in parallel mode (e.g., \u003ccode class=\"literal\"\u003esetseed\u003c/code\u003e cannot be executed other than by the group leader because a change made by another process would not be reflected in the leader). In general, if a function is labeled as being safe when it is restricted or unsafe, or if it is labeled as being restricted when it is in fact unsafe, it may throw errors or produce wrong answers when used in a parallel query. C-language functions could in theory exhibit totally undefined behavior if mislabeled, since there is no way for the system to protect itself against arbitrary C code, but in most likely cases the result will be no worse than for any other function. If in doubt, functions should be labeled as \u003ccode class=\"literal\"\u003eUNSAFE\u003c/code\u003e, which is the default.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eCOST\u003c/code\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003eexecution_cost\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eA positive number giving the estimated execution cost for the function, in units of \u003ca href=\"/docs/18/runtime-config-query.html#GUC-CPU-OPERATOR-COST\"\u003ecpu_operator_cost\u003c/a\u003e. If the function returns a set, this is the cost per returned row. If the cost is not specified, 1 unit is assumed for C-language and internal functions, and 100 units for functions in all other languages. Larger values cause the planner to try to avoid evaluating the function more often than necessary.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eROWS\u003c/code\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003eresult_rows\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eA positive number giving the estimated number of rows that the planner should expect the function to return. This is only allowed when the function is declared to return a set. The default assumption is 1000 rows.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eSUPPORT\u003c/code\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003esupport_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe name (optionally schema-qualified) of a \u003cem class=\"firstterm\"\u003eplanner support function\u003c/em\u003e to use for this function. See \u003ca href=\"/docs/18/xfunc-optimization.html\" title=\"36.11. Function Optimization Information\"\u003eSection 36.11\u003c/a\u003e for details. You must be superuser to use this option.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003econfiguration_parameter\u003c/code\u003e\u003c/em\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003evalue\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe \u003ccode class=\"literal\"\u003eSET\u003c/code\u003e clause causes the specified configuration parameter to be set to the specified value when the function is entered, and then restored to its prior value when the function exits. \u003ccode class=\"literal\"\u003eSET FROM CURRENT\u003c/code\u003e saves the value of the parameter that is current when \u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e is executed as the value to be applied when the function is entered.\u003c/p\u003e\u003cp\u003eIf a \u003ccode class=\"literal\"\u003eSET\u003c/code\u003e clause is attached to a function, then the effects of a \u003ccode class=\"command\"\u003eSET LOCAL\u003c/code\u003e command executed inside the function for the same variable are restricted to the function: the configuration parameter's prior value is still restored at function exit. However, an ordinary \u003ccode class=\"command\"\u003eSET\u003c/code\u003e command (without \u003ccode class=\"literal\"\u003eLOCAL\u003c/code\u003e) overrides the \u003ccode class=\"literal\"\u003eSET\u003c/code\u003e clause, much as it would do for a previous \u003ccode class=\"command\"\u003eSET LOCAL\u003c/code\u003e command: the effects of such a command will persist after function exit, unless the current transaction is rolled back.\u003c/p\u003e\u003cp\u003eSee \u003ca href=\"/docs/18/sql-set.html\" title=\"SET\"\u003e\u003cspan class=\"refentrytitle\"\u003eSET\u003c/span\u003e\u003c/a\u003e and \u003ca href=\"/docs/18/runtime-config.html\" title=\"Chapter 19. Server Configuration\"\u003eChapter 19\u003c/a\u003e for more information about allowed parameter names and values.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefinition\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eA string constant defining the function; the meaning depends on the language. It can be an internal function name, the path to an object file, an SQL command, or text in a procedural language.\u003c/p\u003e\u003cp\u003eIt is often helpful to use dollar quoting (see \u003ca href=\"/docs/18/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING\" title=\"4.1.2.4. Dollar-Quoted String Constants\"\u003eSection 4.1.2.4\u003c/a\u003e) to write the function definition string, rather than the normal single quote syntax. Without dollar quoting, any single quotes or backslashes in the function definition must be escaped by doubling them.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eobj_file\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003elink_symbol\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThis form of the \u003ccode class=\"literal\"\u003eAS\u003c/code\u003e clause is used for dynamically loadable C language functions when the function name in the C language source code is not the same as the name of the SQL function. The string \u003cem class=\"replaceable\"\u003e\u003ccode\u003eobj_file\u003c/code\u003e\u003c/em\u003e is the name of the shared library file containing the compiled C function, and is interpreted as for the \u003ca href=\"/docs/18/sql-load.html\" title=\"LOAD\"\u003e\u003ccode class=\"command\"\u003eLOAD\u003c/code\u003e\u003c/a\u003e command. The string \u003cem class=\"replaceable\"\u003e\u003ccode\u003elink_symbol\u003c/code\u003e\u003c/em\u003e is the function's link symbol, that is, the name of the function in the C language source code. If the link symbol is omitted, it is assumed to be the same as the name of the SQL function being defined. The C names of all functions must be different, so you must give overloaded C functions different C names (for example, use the argument types as part of the C names).\u003c/p\u003e\u003cp\u003eWhen repeated \u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e calls refer to the same object file, the file is only loaded once per session. To unload and reload the file (perhaps during development), start a new session.\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003eThe body of a \u003ccode class=\"literal\"\u003eLANGUAGE SQL\u003c/code\u003e function. This can either be a single statement\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eRETURN \u003cem class=\"replaceable\"\u003e\u003ccode\u003eexpression\u003c/code\u003e\u003c/em\u003e\n\u003c/pre\u003e\u003cp\u003eor a block\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eBEGIN ATOMIC\n  \u003cem class=\"replaceable\"\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\n  \u003cem class=\"replaceable\"\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\n  ...\n  \u003cem class=\"replaceable\"\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\nEND\n\u003c/pre\u003e\u003cp\u003eThis is similar to writing the text of the function body as a string constant (see \u003cem class=\"replaceable\"\u003e\u003ccode\u003edefinition\u003c/code\u003e\u003c/em\u003e above), but there are some differences: This form only works for \u003ccode class=\"literal\"\u003eLANGUAGE SQL\u003c/code\u003e, the string constant form works for all languages. This form is parsed at function definition time, the string constant form is parsed at execution time; therefore this form cannot support polymorphic argument types and other constructs that are not resolvable at function definition time. This form tracks dependencies between the function and objects used in the function body, so \u003ccode class=\"literal\"\u003eDROP ... CASCADE\u003c/code\u003e will work correctly, whereas the form using string literals may leave dangling functions. Finally, this form is more compatible with the SQL standard and other SQL implementations.\u003c/p\u003e\u003c/dd\u003e\u003c/dl\u003e\u003c/div\u003e","key":"parameters","title":"Parameters"},{"html":"\u003cp\u003e\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e allows function \u003cem class=\"firstterm\"\u003eoverloading\u003c/em\u003e; that is, the same name can be used for several different functions so long as they have distinct input argument types. Whether or not you use it, this capability entails security precautions when calling functions in databases where some users mistrust other users; see \u003ca href=\"/docs/18/typeconv-func.html\" title=\"10.3. Functions\"\u003eSection 10.3\u003c/a\u003e.\u003c/p\u003e\u003cp\u003eTwo functions are considered the same if they have the same names and \u003cspan class=\"emphasis\"\u003e\u003cem\u003einput\u003c/em\u003e\u003c/span\u003e argument types, ignoring any \u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e parameters. Thus for example these declarations conflict:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION foo(int) ...\nCREATE FUNCTION foo(int, out text) ...\n\u003c/pre\u003e\u003cp\u003eFunctions that have different argument type lists will not be considered to conflict at creation time, but if defaults are provided they might conflict in use. For example, consider\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION foo(int) ...\nCREATE FUNCTION foo(int, int default 42) ...\n\u003c/pre\u003e\u003cp\u003eA call \u003ccode class=\"literal\"\u003efoo(10)\u003c/code\u003e will fail due to the ambiguity about which function should be called.\u003c/p\u003e","key":"other","title":"Overloading"},{"html":"\u003cp\u003eThe full \u003cacronym\u003eSQL\u003c/acronym\u003e type syntax is allowed for declaring a function's arguments and return value. However, parenthesized type modifiers (e.g., the precision field for type \u003ccode class=\"type\"\u003enumeric\u003c/code\u003e) are discarded by \u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e. Thus for example \u003ccode class=\"literal\"\u003eCREATE FUNCTION foo (varchar(10)) ...\u003c/code\u003e is exactly the same as \u003ccode class=\"literal\"\u003eCREATE FUNCTION foo (varchar) ...\u003c/code\u003e.\u003c/p\u003e\u003cp\u003eWhen replacing an existing function with \u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e, there are restrictions on changing parameter names. You cannot change the name already assigned to any input parameter (although you can add names to parameters that had none before). If there is more than one output parameter, you cannot change the names of the output parameters, because that would change the column names of the anonymous composite type that describes the function's result. These restrictions are made to ensure that existing calls of the function do not stop working when it is replaced.\u003c/p\u003e\u003cp\u003eIf a function is declared \u003ccode class=\"literal\"\u003eSTRICT\u003c/code\u003e with a \u003ccode class=\"literal\"\u003eVARIADIC\u003c/code\u003e argument, the strictness check tests that the variadic array \u003cspan class=\"emphasis\"\u003e\u003cem\u003eas a whole\u003c/em\u003e\u003c/span\u003e is non-null. The function will still be called if the array has null elements.\u003c/p\u003e","key":"notes","title":"Notes"},{"html":"\u003cp\u003eAdd two integers using an SQL function:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION add(integer, integer) RETURNS integer\n    AS 'select $1 + $2;'\n    LANGUAGE SQL\n    IMMUTABLE\n    RETURNS NULL ON NULL INPUT;\n\u003c/pre\u003e\u003cp\u003eThe same function written in a more SQL-conforming style, using argument names and an unquoted body:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION add(a integer, b integer) RETURNS integer\n    LANGUAGE SQL\n    IMMUTABLE\n    RETURNS NULL ON NULL INPUT\n    RETURN a + b;\n\u003c/pre\u003e\u003cp\u003eIncrement an integer, making use of an argument name, in \u003cspan class=\"application\"\u003ePL/pgSQL\u003c/span\u003e:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$\n        BEGIN\n                RETURN i + 1;\n        END;\n$$ LANGUAGE plpgsql;\n\u003c/pre\u003e\u003cp\u003eReturn a record containing multiple output parameters:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION dup(in int, out f1 int, out f2 text)\n    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003eYou can do the same thing more verbosely with an explicitly named composite type:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE dup_result AS (f1 int, f2 text);\n\nCREATE FUNCTION dup(int) RETURNS dup_result\n    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003eAnother way to return multiple columns is to use a \u003ccode class=\"literal\"\u003eTABLE\u003c/code\u003e function:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION dup(int) RETURNS TABLE(f1 int, f2 text)\n    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003eHowever, a \u003ccode class=\"literal\"\u003eTABLE\u003c/code\u003e function is different from the preceding examples, because it actually returns a \u003cspan class=\"emphasis\"\u003e\u003cem\u003eset\u003c/em\u003e\u003c/span\u003e of records, not just one record.\u003c/p\u003e","key":"examples","title":"Examples"},{"html":"\u003cp\u003eBecause a \u003ccode class=\"literal\"\u003eSECURITY DEFINER\u003c/code\u003e function is executed with the privileges of the user that owns it, care is needed to ensure that the function cannot be misused. For security, \u003ca href=\"/docs/18/runtime-config-client.html#GUC-SEARCH-PATH\"\u003esearch_path\u003c/a\u003e should be set to exclude any schemas writable by untrusted users. This prevents malicious users from creating objects (e.g., tables, functions, and operators) that mask objects intended to be used by the function. Particularly important in this regard is the temporary-table schema, which is searched first by default, and is normally writable by anyone. A secure arrangement can be obtained by forcing the temporary schema to be searched last. To do this, write \u003ccode class=\"literal\"\u003epg_temp\u003c/code\u003e as the last entry in \u003ccode class=\"varname\"\u003esearch_path\u003c/code\u003e. This function illustrates safe usage:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION check_password(uname TEXT, pass TEXT)\nRETURNS BOOLEAN AS $$\nDECLARE passed BOOLEAN;\nBEGIN\n        SELECT  (pwd = $2) INTO passed\n        FROM    pwds\n        WHERE   username = $1;\n\n        RETURN passed;\nEND;\n$$  LANGUAGE plpgsql\n    SECURITY DEFINER\n    -- Set a secure search_path: trusted schema(s), then 'pg_temp'.\n    SET search_path = admin, pg_temp;\n\u003c/pre\u003e\u003cp\u003eThis function's intention is to access a table \u003ccode class=\"literal\"\u003eadmin.pwds\u003c/code\u003e. But without the \u003ccode class=\"literal\"\u003eSET\u003c/code\u003e clause, or with a \u003ccode class=\"literal\"\u003eSET\u003c/code\u003e clause mentioning only \u003ccode class=\"literal\"\u003eadmin\u003c/code\u003e, the function could be subverted by creating a temporary table named \u003ccode class=\"literal\"\u003epwds\u003c/code\u003e.\u003c/p\u003e\u003cp\u003eIf the security definer function intends to create roles, and if it is running as a non-superuser, \u003ccode class=\"varname\"\u003ecreaterole_self_grant\u003c/code\u003e should also be set to a known value using the \u003ccode class=\"literal\"\u003eSET\u003c/code\u003e clause.\u003c/p\u003e\u003cp\u003eAnother point to keep in mind is that by default, execute privilege is granted to \u003ccode class=\"literal\"\u003ePUBLIC\u003c/code\u003e for newly created functions (see \u003ca href=\"/docs/18/ddl-priv.html\" title=\"5.8. Privileges\"\u003eSection 5.8\u003c/a\u003e for more information). Frequently you will wish to restrict use of a security definer function to only some users. To do that, you must revoke the default \u003ccode class=\"literal\"\u003ePUBLIC\u003c/code\u003e privileges and then grant execute privilege selectively. To avoid having a window where the new function is accessible to all, create it and set the privileges within a single transaction. For example:\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eBEGIN;\nCREATE FUNCTION check_password(uname TEXT, pass TEXT) ... SECURITY DEFINER;\nREVOKE ALL ON FUNCTION check_password(uname TEXT, pass TEXT) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION check_password(uname TEXT, pass TEXT) TO admins;\nCOMMIT;\n\u003c/pre\u003e","key":"other","title":"Writing SECURITY DEFINER Functions Safely"},{"html":"\u003cp\u003eA \u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e command is defined in the SQL standard. The \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e implementation can be used in a compatible way but has many extensions. Conversely, the SQL standard specifies a number of optional features that are not implemented in \u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e.\u003c/p\u003e\u003cp\u003eThe following are important compatibility issues:\u003c/p\u003e\u003cdiv class=\"itemizedlist\"\u003e\u003cul class=\"itemizedlist\"\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eOR REPLACE\u003c/code\u003e is a PostgreSQL extension.\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003eFor compatibility with some other database systems, \u003cem class=\"replaceable\"\u003e\u003ccode\u003eargmode\u003c/code\u003e\u003c/em\u003e can be written either before or after \u003cem class=\"replaceable\"\u003e\u003ccode\u003eargname\u003c/code\u003e\u003c/em\u003e. But only the first way is standard-compliant.\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003eFor parameter defaults, the SQL standard specifies only the syntax with the \u003ccode class=\"literal\"\u003eDEFAULT\u003c/code\u003e key word. The syntax with \u003ccode class=\"literal\"\u003e=\u003c/code\u003e is used in T-SQL and Firebird.\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003eThe \u003ccode class=\"literal\"\u003eSETOF\u003c/code\u003e modifier is a PostgreSQL extension.\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003eOnly \u003ccode class=\"literal\"\u003eSQL\u003c/code\u003e is standardized as a language.\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003eAll other attributes except \u003ccode class=\"literal\"\u003eCALLED ON NULL INPUT\u003c/code\u003e and \u003ccode class=\"literal\"\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e are not standardized.\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003eFor the body of \u003ccode class=\"literal\"\u003eLANGUAGE SQL\u003c/code\u003e functions, the SQL standard only specifies the \u003cem class=\"replaceable\"\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e form.\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/div\u003e\u003cp\u003eSimple \u003ccode class=\"literal\"\u003eLANGUAGE SQL\u003c/code\u003e functions can be written in a way that is both standard-conforming and portable to other implementations. More complex functions using advanced features, optimization attributes, or other languages will necessarily be specific to PostgreSQL in a significant way.\u003c/p\u003e","key":"compatibility","title":"Compatibility"},{"html":"\u003cspan class=\"simplelist\"\u003e\u003ca href=\"/wiki/sql/alter-function/?v=18\" title=\"ALTER FUNCTION\"\u003e\u003cspan class=\"refentrytitle\"\u003eALTER FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/drop-function/?v=18\" title=\"DROP FUNCTION\"\u003e\u003cspan class=\"refentrytitle\"\u003eDROP FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/grant/?v=18\" title=\"GRANT\"\u003e\u003cspan class=\"refentrytitle\"\u003eGRANT\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/load/?v=18\" title=\"LOAD\"\u003e\u003cspan class=\"refentrytitle\"\u003eLOAD\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/revoke/?v=18\" title=\"REVOKE\"\u003e\u003cspan class=\"refentrytitle\"\u003eREVOKE\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e","key":"see_also","title":"See Also"}],"sections_same_as":"","slug":"18","synopsis_html":"CREATE [ OR REPLACE ] FUNCTION\n    \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e ( [ [ \u003cem class=\"replaceable\"\u003e\u003ccode\u003eargmode\u003c/code\u003e\u003c/em\u003e ] [ \u003cem class=\"replaceable\"\u003e\u003ccode\u003eargname\u003c/code\u003e\u003c/em\u003e ] \u003cem class=\"replaceable\"\u003e\u003ccode\u003eargtype\u003c/code\u003e\u003c/em\u003e [ { DEFAULT | = } \u003cem class=\"replaceable\"\u003e\u003ccode\u003edefault_expr\u003c/code\u003e\u003c/em\u003e ] [, ...] ] )\n    [ RETURNS \u003cem class=\"replaceable\"\u003e\u003ccode\u003erettype\u003c/code\u003e\u003c/em\u003e\n      | RETURNS TABLE ( \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_type\u003c/code\u003e\u003c/em\u003e [, ...] ) ]\n  { LANGUAGE \u003cem class=\"replaceable\"\u003e\u003ccode\u003elang_name\u003c/code\u003e\u003c/em\u003e\n    | TRANSFORM { FOR TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_name\u003c/code\u003e\u003c/em\u003e } [, ... ]\n    | WINDOW\n    | { IMMUTABLE | STABLE | VOLATILE }\n    | [ NOT ] LEAKPROOF\n    | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }\n    | { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }\n    | PARALLEL { UNSAFE | RESTRICTED | SAFE }\n    | COST \u003cem class=\"replaceable\"\u003e\u003ccode\u003eexecution_cost\u003c/code\u003e\u003c/em\u003e\n    | ROWS \u003cem class=\"replaceable\"\u003e\u003ccode\u003eresult_rows\u003c/code\u003e\u003c/em\u003e\n    | SUPPORT \u003cem class=\"replaceable\"\u003e\u003ccode\u003esupport_function\u003c/code\u003e\u003c/em\u003e\n    | SET \u003cem class=\"replaceable\"\u003e\u003ccode\u003econfiguration_parameter\u003c/code\u003e\u003c/em\u003e { TO \u003cem class=\"replaceable\"\u003e\u003ccode\u003evalue\u003c/code\u003e\u003c/em\u003e | = \u003cem class=\"replaceable\"\u003e\u003ccode\u003evalue\u003c/code\u003e\u003c/em\u003e | FROM CURRENT }\n    | AS '\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefinition\u003c/code\u003e\u003c/em\u003e'\n    | AS '\u003cem class=\"replaceable\"\u003e\u003ccode\u003eobj_file\u003c/code\u003e\u003c/em\u003e', '\u003cem class=\"replaceable\"\u003e\u003ccode\u003elink_symbol\u003c/code\u003e\u003c/em\u003e'\n    | \u003cem class=\"replaceable\"\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e\n  } ...","synopsis_text":"CREATE [ OR REPLACE ] FUNCTION\nname ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )\n[ RETURNS rettype\n| RETURNS TABLE ( column_name column_type [, ...] ) ]\n{ LANGUAGE lang_name\n| TRANSFORM { FOR TYPE type_name } [, ... ]\n| WINDOW\n| { IMMUTABLE | STABLE | VOLATILE }\n| [ NOT ] LEAKPROOF\n| { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }\n| { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }\n| PARALLEL { UNSAFE | RESTRICTED | SAFE }\n| COST execution_cost\n| ROWS result_rows\n| SUPPORT support_function\n| SET configuration_parameter { TO value | = value | FROM CURRENT }\n| AS 'definition'\n| AS 'obj_file', 'link_symbol'\n| sql_body\n} ..."},"ManualEvidence":{},"MeasuredEvidence":{}},"Text":{"Collection":"sql","Key":"create-function","SourceDatabase":"pgweb","Version":"18","Locale":"zh-Hans","Title":"CREATE FUNCTION","Summary":"定义一个新函数","BodyHTML":"\u003cpre\u003eCREATE [ OR REPLACE ] FUNCTION\nname ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )\n[ RETURNS rettype\n| RETURNS TABLE ( column_name column_type [, ...] ) ]\n{ LANGUAGE lang_name\n| TRANSFORM { FOR TYPE type_name } [, ... ]\n| WINDOW\n| { IMMUTABLE | STABLE | VOLATILE }\n| [ NOT ] LEAKPROOF\n| { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }\n| { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }\n| PARALLEL { UNSAFE | RESTRICTED | SAFE }\n| COST execution_cost\n| ROWS result_rows\n| SUPPORT support_function\n| SET configuration_parameter { TO value | = value | FROM CURRENT }\n| AS \u0026#39;definition\u0026#39;\n| AS \u0026#39;obj_file\u0026#39;, \u0026#39;link_symbol\u0026#39;\n| sql_body\n} ...\u003c/pre\u003e\u003csection\u003e\u003ch2\u003e描述\u003c/h2\u003e\u003cp\u003e\u003ccode\u003eCREATE FUNCTION\u003c/code\u003e定义一个新函数。\u003ccode\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e将创建一个新函数，或者替换现有定义。要定义函数，用户必须具有该语言上的\u003ccode\u003eUSAGE\u003c/code\u003e权限。\u003c/p\u003e\u003cp\u003e如果包含模式名，那么该函数会被创建在指定的模式中。否则，它会被创建在当前模式中。新函数的名称不能匹配同一模式中任何具有相同输入参数类型的现有函数或过程。不过，不同参数类型的函数和过程能够共享一个名字（这被称为\u003cem\u003e重载\u003c/em\u003e）。\u003c/p\u003e\u003cp\u003e要替换一个现有函数的当前定义，可以使用\u003ccode\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e。但不能用这种方式更改函数的名称或者参数类型（如果尝试这样做，实际上就会创建一个新的不同函数）。此外，\u003ccode\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e也不允许更改现有函数的返回类型。要做到这一点，必须删除该函数并重新创建。（使用\u003ccode\u003eOUT\u003c/code\u003e参数时，这意味着除非删除该函数，否则不能更改任何\u003ccode\u003eOUT\u003c/code\u003e参数的类型。）\u003c/p\u003e\u003cp\u003e当\u003ccode\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e被用来替换一个现有函数时，该函数的拥有权和权限不会改变。所有其他的函数属性会按照该命令中指定的或者隐含的值赋值。必须拥有（包括成为拥有角色的成员）该函数才能替换它。\u003c/p\u003e\u003cp\u003e如果删除函数后再重新创建，新函数就不再是旧函数的同一实体；你将必须删除引用旧函数的现有规则、视图、触发器等。使用\u003ccode\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e可以在不破坏引用该函数的对象的情况下更改函数定义。此外，\u003ccode\u003eALTER FUNCTION\u003c/code\u003e还可用于更改现有函数的大多数辅助属性。\u003c/p\u003e\u003cp\u003e创建该函数的用户将成为该函数的拥有者。\u003c/p\u003e\u003cp\u003e要创建一个函数，你必须拥有参数类型和返回类型上的\u003ccode\u003eUSAGE\u003c/code\u003e权限。\u003c/p\u003e\u003cp\u003e有关编写函数的详细信息，请参阅\u003ca href=\"/docs/18/xfunc.html\" rel=\"nofollow\"\u003e第 36.3 节\u003c/a\u003e。\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e参数\u003c/h2\u003e\u003cdiv\u003e\u003cdl\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e要创建的函数名称（可以被模式限定）。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003eargmode\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e参数的模式可以是：\u003ccode\u003eIN\u003c/code\u003e、\u003ccode\u003eOUT\u003c/code\u003e、\u003ccode\u003eINOUT\u003c/code\u003e或者\u003ccode\u003eVARIADIC\u003c/code\u003e。如果省略，则默认为\u003ccode\u003eIN\u003c/code\u003e。只有\u003ccode\u003eOUT\u003c/code\u003e参数可以跟在\u003ccode\u003eVARIADIC\u003c/code\u003e参数之后。此外，\u003ccode\u003eOUT\u003c/code\u003e和\u003ccode\u003eINOUT\u003c/code\u003e参数不能与\u003ccode\u003eRETURNS TABLE\u003c/code\u003e记法一起使用。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003eargname\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e参数的名称。某些语言（包括 SQL 和 PL/pgSQL）允许在函数体中使用该名称。对于其他语言，就函数本身而言，输入参数的名称只是额外文档；但你可以在调用函数时使用输入参数名来提高可读性（见\u003ca href=\"/docs/18/sql-syntax-calling-funcs.html\" rel=\"nofollow\"\u003e第 4.3 节\u003c/a\u003e）。无论如何，输出参数的名称很重要，因为它定义了结果行类型中的列名。（如果省略输出参数的名称，系统将选择一个默认列名。）\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003eargtype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该函数参数（如果有）的数据类型（可以是模式限定的）。参数类型可以是基础类型、复合类型或者域类型，也可以引用一个表列的类型。\u003c/p\u003e\u003cp\u003e根据实现语言的不同，也可能允许指定诸如\u003ccode\u003ecstring\u003c/code\u003e这样的\u003cspan\u003e“\u003cspan\u003e伪类型\u003c/span\u003e”\u003c/span\u003e。伪类型表示实际参数类型要么没有被完整指定，要么不属于普通 SQL 数据类型集合。\u003c/p\u003e\u003cp\u003e写成\u003ccode\u003e\u003cem\u003e\u003ccode\u003etable_name\u003c/code\u003e\u003c/em\u003e.\u003cem\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e%TYPE\u003c/code\u003e即可引用一个列的类型。使用这种特性有时有助于让函数独立于表定义的变化。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003edefault_expr\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e如果未指定该参数，则用作默认值的表达式。该表达式必须能被强制转换为该参数的类型。只有输入参数（包括\u003ccode\u003eINOUT\u003c/code\u003e）才能有默认值。所有跟在具有默认值参数之后的输入参数也都必须有默认值。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003erettype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该函数的返回数据类型（可以是模式限定的）。返回类型可以是基础类型、复合类型或者域类型，也可以引用一个表列的类型。根据实现语言的不同，也可能允许指定诸如\u003ccode\u003ecstring\u003c/code\u003e这样的\u003cspan\u003e“\u003cspan\u003e伪类型\u003c/span\u003e”\u003c/span\u003e。如果函数不应该返回值，请把返回类型指定为\u003ccode\u003evoid\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e当存在\u003ccode\u003eOUT\u003c/code\u003e或\u003ccode\u003eINOUT\u003c/code\u003e参数时，可以省略\u003ccode\u003eRETURNS\u003c/code\u003e子句。如果写出该子句，它必须与输出参数所隐含的结果类型一致：如果有多个输出参数，则为\u003ccode\u003eRECORD\u003c/code\u003e；如果只有一个输出参数，则为该输出参数的类型。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eSETOF\u003c/code\u003e修饰符表示该函数将返回一组项，而不是单个项。\u003c/p\u003e\u003cp\u003e写成\u003ccode\u003e\u003cem\u003e\u003ccode\u003etable_name\u003c/code\u003e\u003c/em\u003e.\u003cem\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e%TYPE\u003c/code\u003e即可引用一个列的类型。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003eRETURNS TABLE\u003c/code\u003e语法中输出列的名称。这实际上是声明一个具名\u003ccode\u003eOUT\u003c/code\u003e参数的另一种方式，只不过\u003ccode\u003eRETURNS TABLE\u003c/code\u003e还隐含了\u003ccode\u003eRETURNS SETOF\u003c/code\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003ecolumn_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003eRETURNS TABLE\u003c/code\u003e语法中的输出列的数据类型。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003elang_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e用以实现该函数的语言的名称。可以是\u003ccode\u003esql\u003c/code\u003e、\u003ccode\u003ec\u003c/code\u003e、\u003ccode\u003einternal\u003c/code\u003e或者一个用户定义的过程语言的名称，例如\u003ccode\u003eplpgsql\u003c/code\u003e。如果指定了\u003cem\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e，则默认值为\u003ccode\u003esql\u003c/code\u003e。使用单引号将名称括起来已废弃，并要求大小写匹配。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003eTRANSFORM { FOR TYPE \u003cem\u003e\u003ccode\u003etype_name\u003c/code\u003e\u003c/em\u003e } [, ... ] }\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e列出调用该函数时应应用的转换。转换在 SQL 类型和语言相关的数据类型之间进行变换，详见\u003ca href=\"/docs/18/sql-createtransform.html\" title=\"CREATE TRANSFORM\" rel=\"nofollow\"\u003e\u003cspan\u003eCREATE TRANSFORM\u003c/span\u003e\u003c/a\u003e。过程语言实现通常把有关内置类型的知识硬编码在代码中，因此那些不需要列举在这里。如果一种过程语言实现不知道如何处理某种类型且没有提供转换，它将回退到默认的数据类型转换行为，但这取决于具体实现。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003eWINDOW\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003eWINDOW\u003c/code\u003e表示该函数是\u003cem\u003e窗口函数\u003c/em\u003e而不是普通函数。目前这只对用 C 编写的函数有用。在替换现有函数定义时，不能更改\u003ccode\u003eWINDOW\u003c/code\u003e属性。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003eIMMUTABLE\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan\u003e\u003ccode\u003eSTABLE\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan\u003e\u003ccode\u003eVOLATILE\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e这些属性会告诉查询优化器该函数的行为。最多只能指定其中一个。如果这些属性都没有出现，则默认假定为\u003ccode\u003eVOLATILE\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eIMMUTABLE\u003c/code\u003e表示该函数不能修改数据库，并且在给定相同参数值时总会返回相同结果；也就是说，它不会执行数据库查找，也不会以其他方式使用未直接出现在其参数列表中的信息。如果给出此选项，任何使用全常量参数对该函数的调用都可以立即替换为该函数值。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eSTABLE\u003c/code\u003e表示该函数不能修改数据库，并且在一次表扫描内，对于相同参数值会一致地返回相同结果，但其结果可能在不同 SQL 语句之间发生变化。这适用于结果依赖于数据库查找、参数变量（例如当前时区）等的函数。（对于希望查询由当前命令修改过的行的\u003ccode\u003eAFTER\u003c/code\u003e触发器，这样做并不合适。）另请注意，\u003ccode\u003ecurrent_timestamp\u003c/code\u003e函数族也属于稳定函数，因为它们的值在一个事务内不会变化。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eVOLATILE\u003c/code\u003e表示该函数的值即使在一次表扫描内也可能发生变化，因此无法进行任何优化。从这个意义上说，真正不稳定的数据库函数相对较少；一些例子是\u003ccode\u003erandom()\u003c/code\u003e、\u003ccode\u003ecurrval()\u003c/code\u003e、\u003ccode\u003etimeofday()\u003c/code\u003e。但请注意，任何有副作用的函数都必须归类为不稳定，即使其结果相当可预测，也必须如此，以防其调用被优化掉；例如\u003ccode\u003esetval()\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e更多细节见\u003ca href=\"/docs/18/xfunc-volatility.html\" rel=\"nofollow\"\u003e第 36.7 节\u003c/a\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003eLEAKPROOF\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003eLEAKPROOF\u003c/code\u003e表示该函数没有副作用。除返回值外，它不会泄露其参数的任何信息。例如，对某些参数值会抛出错误而对另一些不会，或者在错误消息中包含参数值的函数，都不是防泄漏的。这会影响系统如何执行针对使用\u003ccode\u003esecurity_barrier\u003c/code\u003e选项创建的视图或启用了行级安全的表的查询。为了防止数据被无意暴露，系统会先强制执行安全策略和安全屏障视图中的条件，再执行查询本身中包含非防泄漏函数的用户提供条件。被标记为防泄漏的函数和操作符被视为可信，因此可以在安全策略和安全屏障视图的条件之前执行。此外，不接受参数的函数，或者没有从安全屏障视图或表中接收到任何参数的函数，即使未标记为防泄漏，也可以在安全条件之前执行。参见\u003ca href=\"/docs/18/sql-createview.html\" title=\"CREATE VIEW\" rel=\"nofollow\"\u003e\u003cspan\u003eCREATE VIEW\u003c/span\u003e\u003c/a\u003e和\u003ca href=\"/docs/18/rules-privileges.html\" rel=\"nofollow\"\u003e第 39.5 节\u003c/a\u003e。此选项只能由超级用户设置。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003eCALLED ON NULL INPUT\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan\u003e\u003ccode\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan\u003e\u003ccode\u003eSTRICT\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003eCALLED ON NULL INPUT\u003c/code\u003e（默认）表示当某些参数为空值时，仍会正常调用该函数。如果有需要，则由函数作者负责检查空值并作出适当响应。\u003c/p\u003e\u003cp\u003e\u003ccode\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e或\u003ccode\u003eSTRICT\u003c/code\u003e表示只要任一参数为空值，该函数总是返回空值。如果指定了这个选项，那么在参数中出现空值时不会执行该函数，而是自动假定结果为空值。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003e[\u003cspan\u003eEXTERNAL\u003c/span\u003e] SECURITY INVOKER\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan\u003e\u003ccode\u003e[\u003cspan\u003eEXTERNAL\u003c/span\u003e] SECURITY DEFINER\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003eSECURITY INVOKER\u003c/code\u003e表示要以调用它的用户的权限来执行该函数。这是默认值。\u003ccode\u003eSECURITY DEFINER\u003c/code\u003e指定要以拥有它的用户的权限来执行该函数。有关如何安全地编写\u003ccode\u003eSECURITY DEFINER\u003c/code\u003e函数的信息，见\u003ca href=\"/docs/18/sql-createfunction.html#SQL-CREATEFUNCTION-SECURITY\" title=\"安全地编写 SECURITY DEFINER函数\" rel=\"nofollow\"\u003e下文\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e为了符合 SQL，允许使用关键字\u003ccode\u003eEXTERNAL\u003c/code\u003e。但它是可选的，因为与 SQL 不同，这个特性适用于所有函数，而不仅仅是外部函数。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003ePARALLEL\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003ePARALLEL UNSAFE\u003c/code\u003e表示该函数不能在并行模式中执行；SQL 语句中只要出现这类函数就会强制使用串行执行计划。这是默认选项。\u003ccode\u003ePARALLEL RESTRICTED\u003c/code\u003e表示该函数可以在并行模式中执行，但只能在并行组领导者进程中执行。\u003ccode\u003ePARALLEL SAFE\u003c/code\u003e表示该函数可以在并行模式下不受限制地执行，包括在并行工作进程中执行。\u003c/p\u003e\u003cp\u003e如果函数会修改任何数据库状态、改变事务状态（使用子事务进行错误恢复除外）、访问序列（例如调用\u003ccode\u003ecurrval\u003c/code\u003e），或者对设置做持久性更改，则应标记为并行不安全。如果函数访问临时表、客户端连接状态、游标、预备语句，或者系统无法在并行模式下同步的其他后端本地状态，则应标记为并行受限（例如，\u003ccode\u003esetseed\u003c/code\u003e只能由组领导者执行，因为其他进程所做的更改不会反映到领导者中）。一般来说，如果函数实际上是受限或不安全却被标记为安全，或者实际上不安全却被标记为受限，那么在并行查询中使用它时可能会抛出错误或产生错误结果。C 语言函数若被错误标记，理论上甚至可能表现出完全未定义的行为，因为系统无法保护自己不受任意 C 代码的影响；不过在大多数情况下，结果通常也不会比其他函数更糟。如果拿不准，函数就应标记为\u003ccode\u003eUNSAFE\u003c/code\u003e，这也是默认值。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003eCOST\u003c/code\u003e \u003cem\u003e\u003ccode\u003eexecution_cost\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e一个正数，给出该函数的估计执行代价，单位为\u003ca href=\"/docs/18/runtime-config-query.html#GUC-CPU-OPERATOR-COST\" rel=\"nofollow\"\u003ecpu_operator_cost\u003c/a\u003e。如果该函数返回一个集合，则这是每个返回行的代价。如果未指定代价，则对 C 语言和内部函数假定为 1 个单位，对其他所有语言的函数假定为 100 个单位。较大的值会让规划器尽量避免对该函数进行不必要的频繁求值。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003eROWS\u003c/code\u003e \u003cem\u003e\u003ccode\u003eresult_rows\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e一个正数，给出规划器应预计该函数返回的行数。只有函数被声明为返回集合时才允许使用此项。默认假定为 1000 行。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003eSUPPORT\u003c/code\u003e \u003cem\u003e\u003ccode\u003esupport_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e用于此函数的\u003cem\u003e规划器支持函数\u003c/em\u003e的名称（可选模式限定）。详见\u003ca href=\"/docs/18/xfunc-optimization.html\" rel=\"nofollow\"\u003e第 36.11 节\u003c/a\u003e。使用此选项必须是超级用户。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003econfiguration_parameter\u003c/code\u003e\u003c/em\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003evalue\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003eSET\u003c/code\u003e子句会在进入函数时将指定的配置参数设为给定值，并在函数退出时恢复为先前的值。\u003ccode\u003eSET FROM CURRENT\u003c/code\u003e会把执行\u003ccode\u003eCREATE FUNCTION\u003c/code\u003e时该参数的当前值保存下来，作为进入函数时要应用的值。\u003c/p\u003e\u003cp\u003e如果函数附带了\u003ccode\u003eSET\u003c/code\u003e子句，那么在函数内针对同一变量执行的\u003ccode\u003eSET LOCAL\u003c/code\u003e命令，其效果会被限制在该函数内部：函数退出时，配置参数先前的值仍会被恢复。不过，普通的\u003ccode\u003eSET\u003c/code\u003e命令（不带\u003ccode\u003eLOCAL\u003c/code\u003e）会覆盖\u003ccode\u003eSET\u003c/code\u003e子句，就像它会覆盖先前的\u003ccode\u003eSET LOCAL\u003c/code\u003e命令一样：这类命令的效果会在函数退出后继续保持，除非当前事务被回滚。\u003c/p\u003e\u003cp\u003e关于允许的参数名和值的更多信息，见\u003ca href=\"/docs/18/sql-set.html\" title=\"SET\" rel=\"nofollow\"\u003e\u003cspan\u003eSET\u003c/span\u003e\u003c/a\u003e和\u003ca href=\"/docs/18/runtime-config.html\" rel=\"nofollow\"\u003e第 19 章\u003c/a\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003edefinition\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e一个定义该函数的字符串常量，其含义取决于所用语言。它可以是一个内部函数名称、一个对象文件的路径、一个 SQL 命令，或者用一种过程语言编写的文本。\u003c/p\u003e\u003cp\u003e使用美元引用（见\u003ca href=\"/docs/18/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING\" rel=\"nofollow\"\u003e第 4.1.2.4 节\u003c/a\u003e）来书写函数定义字符串通常会更有帮助，而不是使用普通的单引号语法。如果没有美元引用，函数定义中的任何单引号或者反斜线都必须用双写来转义。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003ccode\u003e\u003cem\u003e\u003ccode\u003eobj_file\u003c/code\u003e\u003c/em\u003e, \u003cem\u003e\u003ccode\u003elink_symbol\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e当 C 语言源代码中的函数名与 SQL 函数的名称不同时，这种形式的\u003ccode\u003eAS\u003c/code\u003e子句用于动态可加载的 C 语言函数。字符串\u003cem\u003e\u003ccode\u003eobj_file\u003c/code\u003e\u003c/em\u003e是包含已编译 C 函数的共享库文件名，其解释方式与\u003ca href=\"/docs/18/sql-load.html\" title=\"LOAD\" rel=\"nofollow\"\u003e\u003ccode\u003eLOAD\u003c/code\u003e\u003c/a\u003e命令相同。字符串\u003cem\u003e\u003ccode\u003elink_symbol\u003c/code\u003e\u003c/em\u003e是该函数的链接符号，也就是该函数在 C 语言源代码中的名称。如果省略链接符号，则假定它与正在定义的 SQL 函数名称相同。所有函数的 C 名称都必须不同，因此必须为重载的 C 函数指定不同的 C 名称（例如把参数类型作为 C 名称的一部分）。\u003c/p\u003e\u003cp\u003e当重复的\u003ccode\u003eCREATE FUNCTION\u003c/code\u003e调用引用同一个对象文件时，该文件在每个会话中只装载一次。要卸载并重新装载该文件（例如在开发期间），请启动一个新会话。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan\u003e\u003cem\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode\u003eLANGUAGE SQL\u003c/code\u003e函数的主体。它可以是单个语句\u003c/p\u003e\u003cpre\u003eRETURN \u003cem\u003e\u003ccode\u003eexpression\u003c/code\u003e\u003c/em\u003e\n\u003c/pre\u003e\u003cp\u003e或者一个语句块\u003c/p\u003e\u003cpre\u003eBEGIN ATOMIC\n  \u003cem\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\n  \u003cem\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\n  ...\n  \u003cem\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\nEND\n\u003c/pre\u003e\u003cp\u003e这类似于将函数体的文本写成字符串常量（见上面的\u003cem\u003e\u003ccode\u003edefinition\u003c/code\u003e\u003c/em\u003e），但有一些不同：此形式仅适用于\u003ccode\u003eLANGUAGE SQL\u003c/code\u003e，字符串常量形式适用于所有语言。此形式在函数定义时解析，字符串常量形式在执行时解析；因此，此形式不能支持多态参数类型以及其他在函数定义时无法解析的构造。此形式跟踪函数和函数体中使用的对象之间的依赖关系，因此 \u003ccode\u003eDROP ... CASCADE\u003c/code\u003e将正常工作，而使用字符串文本的形式可能会留下悬空函数。最后，此形式与 SQL 标准和其他 SQL 实现更加兼容。\u003c/p\u003e\u003c/dd\u003e\u003c/dl\u003e\u003c/div\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e重载\u003c/h2\u003e\u003cp\u003e\u003cspan\u003ePostgreSQL\u003c/span\u003e允许函数\u003cem\u003e重载\u003c/em\u003e；也就是说，只要输入参数类型不同，同一个名称就可以用于多个不同的函数。无论你是否使用这一能力，在某些用户不信任其他用户的数据库中调用函数时，都需要采取安全预防措施；参见\u003ca href=\"/docs/18/typeconv-func.html\" rel=\"nofollow\"\u003e第 10.3 节\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e如果两个函数具有相同的名称和\u003cspan\u003e\u003cem\u003e输入\u003c/em\u003e\u003c/span\u003e参数类型，它们被认为相同（不考虑任何\u003ccode\u003eOUT\u003c/code\u003e参数）。因此这些声明会冲突：\u003c/p\u003e\u003cpre\u003eCREATE FUNCTION foo(int) ...\nCREATE FUNCTION foo(int, out text) ...\n\u003c/pre\u003e\u003cp\u003e参数类型列表不同的函数在创建时不会被视为冲突，但如果提供了默认值，则在使用时可能发生冲突。例如，考虑下面这些声明：\u003c/p\u003e\u003cpre\u003eCREATE FUNCTION foo(int) ...\nCREATE FUNCTION foo(int, int default 42) ...\n\u003c/pre\u003e\u003cp\u003e调用\u003ccode\u003efoo(10)\u003c/code\u003e会失败，因为系统无法确定应该调用哪个函数。\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e注解\u003c/h2\u003e\u003cp\u003e允许使用完整的\u003cacronym\u003eSQL\u003c/acronym\u003e类型语法来声明函数参数和返回值。不过，\u003ccode\u003eCREATE FUNCTION\u003c/code\u003e会丢弃带圆括号的类型修饰符（例如\u003ccode\u003enumeric\u003c/code\u003e类型的精度字段）。因此，\u003ccode\u003eCREATE FUNCTION foo (varchar(10)) ...\u003c/code\u003e与\u003ccode\u003eCREATE FUNCTION foo (varchar) ...\u003c/code\u003e完全等同。\u003c/p\u003e\u003cp\u003e在用\u003ccode\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e替换现有函数时，更改参数名会受到限制。不能更改已经分配给任何输入参数的名称（但可以给先前没有名称的参数补上名称）。如果输出参数多于一个，也不能更改输出参数的名称，因为那会改变描述函数结果的匿名复合类型的列名。这些限制是为了确保函数被替换时，已有的函数调用不会停止工作。\u003c/p\u003e\u003cp\u003e如果一个函数被声明为带有\u003ccode\u003eVARIADIC\u003c/code\u003e参数的\u003ccode\u003eSTRICT\u003c/code\u003e函数，则严格性检查测试的是可变参数数组\u003cspan\u003e\u003cem\u003e作为一个整体\u003c/em\u003e\u003c/span\u003e是否非空。如果该数组包含空值元素，仍会调用该函数。\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e示例\u003c/h2\u003e\u003cp\u003e使用 SQL 函数把两个整数相加：\u003c/p\u003e\u003cpre\u003eCREATE FUNCTION add(integer, integer) RETURNS integer\n    AS \u0026#39;select $1 + $2;\u0026#39;\n    LANGUAGE SQL\n    IMMUTABLE\n    RETURNS NULL ON NULL INPUT;\n\u003c/pre\u003e\u003cp\u003e同一函数也可以用更符合 SQL 标准的风格来编写，使用参数名和不加引号的函数体：\u003c/p\u003e\u003cpre\u003eCREATE FUNCTION add(a integer, b integer) RETURNS integer\n    LANGUAGE SQL\n    IMMUTABLE\n    RETURNS NULL ON NULL INPUT\n    RETURN a + b;\n\u003c/pre\u003e\u003cp\u003e在\u003cspan\u003ePL/pgSQL\u003c/span\u003e中，使用参数名把一个整数加 1：\u003c/p\u003e\u003cpre\u003eCREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$\n        BEGIN\n                RETURN i + 1;\n        END;\n$$ LANGUAGE plpgsql;\n\u003c/pre\u003e\u003cp\u003e返回一个包含多个输出参数的记录：\u003c/p\u003e\u003cpre\u003eCREATE FUNCTION dup(in int, out f1 int, out f2 text)\n    AS $$ SELECT $1, CAST($1 AS text) || \u0026#39; is text\u0026#39; $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003e你也可以用一个显式命名的复合类型，更详细地表达同样的意思：\u003c/p\u003e\u003cpre\u003eCREATE TYPE dup_result AS (f1 int, f2 text);\n\nCREATE FUNCTION dup(int) RETURNS dup_result\n    AS $$ SELECT $1, CAST($1 AS text) || \u0026#39; is text\u0026#39; $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003e另一种返回多列的方法是使用\u003ccode\u003eTABLE\u003c/code\u003e函数：\u003c/p\u003e\u003cpre\u003eCREATE FUNCTION dup(int) RETURNS TABLE(f1 int, f2 text)\n    AS $$ SELECT $1, CAST($1 AS text) || \u0026#39; is text\u0026#39; $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003e不过，\u003ccode\u003eTABLE\u003c/code\u003e函数与前面的示例不同，因为它实际返回的是一\u003cspan\u003e\u003cem\u003e组\u003c/em\u003e\u003c/span\u003e记录，而不只是单条记录。\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e安全地编写 SECURITY DEFINER函数\u003c/h2\u003e\u003cp\u003e因为\u003ccode\u003eSECURITY DEFINER\u003c/code\u003e函数要以拥有它的用户的权限执行，所以必须小心确保该函数不会被滥用。出于安全考虑，应将\u003ca href=\"/docs/18/runtime-config-client.html#GUC-SEARCH-PATH\" rel=\"nofollow\"\u003esearch_path\u003c/a\u003e设置为排除任何可被不受信任用户写入的模式。这可以防止恶意用户创建对象（例如表、函数和操作符）来遮蔽该函数原本打算使用的对象。在这方面尤其重要的是临时表模式；默认情况下它最先被搜索，而且通常任何人都可写。一个安全的安排是强制把临时模式放到搜索顺序的最后。要做到这一点，应把\u003ccode\u003epg_temp\u003c/code\u003e写成\u003ccode\u003esearch_path\u003c/code\u003e中的最后一项。下面这个函数展示了安全用法：\u003c/p\u003e\u003cpre\u003eCREATE FUNCTION check_password(uname TEXT, pass TEXT)\nRETURNS BOOLEAN AS $$\nDECLARE passed BOOLEAN;\nBEGIN\n        SELECT  (pwd = $2) INTO passed\n        FROM    pwds\n        WHERE   username = $1;\n\n        RETURN passed;\nEND;\n$$  LANGUAGE plpgsql\n    SECURITY DEFINER\n    -- 设置一个安全的 search_path：受信的模式，然后是 \u0026#39;pg_temp\u0026#39;。\n    SET search_path = admin, pg_temp;\n\u003c/pre\u003e\u003cp\u003e这个函数的意图是访问\u003ccode\u003eadmin.pwds\u003c/code\u003e表。但如果没有\u003ccode\u003eSET\u003c/code\u003e子句，或者\u003ccode\u003eSET\u003c/code\u003e子句只提到\u003ccode\u003eadmin\u003c/code\u003e，那么该函数就可能因为有人创建一个名为\u003ccode\u003epwds\u003c/code\u003e的临时表而被利用。\u003c/p\u003e\u003cp\u003e如果该\u003ccode\u003eSECURITY DEFINER\u003c/code\u003e函数打算创建角色，并且以非超级用户身份运行，那么还应使用\u003ccode\u003eSET\u003c/code\u003e子句将\u003ccode\u003ecreaterole_self_grant\u003c/code\u003e设置为一个已知值。\u003c/p\u003e\u003cp\u003e另一点需要记住的是，默认情况下，新创建的函数会把执行权限授予\u003ccode\u003ePUBLIC\u003c/code\u003e（详见\u003ca href=\"/docs/18/ddl-priv.html\" rel=\"nofollow\"\u003e第 5.8 节\u003c/a\u003e）。通常你会希望只允许某些用户使用\u003ccode\u003eSECURITY DEFINER\u003c/code\u003e函数。要做到这一点，必须先撤销默认的\u003ccode\u003ePUBLIC\u003c/code\u003e权限，然后有选择地授予执行权限。为了避免新函数在一段时间窗口内对所有人都可访问，应在同一个事务中创建该函数并设置权限。例如：\u003c/p\u003e\u003cpre\u003eBEGIN;\nCREATE FUNCTION check_password(uname TEXT, pass TEXT) ... SECURITY DEFINER;\nREVOKE ALL ON FUNCTION check_password(uname TEXT, pass TEXT) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION check_password(uname TEXT, pass TEXT) TO admins;\nCOMMIT;\n\u003c/pre\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e兼容性\u003c/h2\u003e\u003cp\u003e\u003ccode\u003eCREATE FUNCTION\u003c/code\u003e命令由 SQL 标准定义。\u003cspan\u003ePostgreSQL\u003c/span\u003e的实现可以按兼容方式使用，但也包含许多扩展。反过来，SQL 标准还规定了一些\u003cspan\u003ePostgreSQL\u003c/span\u003e尚未实现的可选特性。\u003c/p\u003e\u003cp\u003e以下是重要的兼容性问题：\u003c/p\u003e\u003cdiv\u003e\u003cul\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eOR REPLACE\u003c/code\u003e是 PostgreSQL 扩展。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e为与某些其他数据库系统兼容，\u003cem\u003e\u003ccode\u003eargmode\u003c/code\u003e\u003c/em\u003e可以写在\u003cem\u003e\u003ccode\u003eargname\u003c/code\u003e\u003c/em\u003e之前或之后，但只有前一种写法符合标准。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e对于参数默认值，SQL 标准只规定了带有\u003ccode\u003eDEFAULT\u003c/code\u003e关键字的语法。带\u003ccode\u003e=\u003c/code\u003e的语法用于 T-SQL 和 Firebird。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e\u003ccode\u003eSETOF\u003c/code\u003e修饰符是 PostgreSQL 扩展。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e只有\u003ccode\u003eSQL\u003c/code\u003e被标准化为一种语言。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e除\u003ccode\u003eCALLED ON NULL INPUT\u003c/code\u003e和\u003ccode\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e之外的所有其他属性都未标准化。\u003c/p\u003e\u003c/li\u003e\u003cli\u003e\u003cp\u003e对于\u003ccode\u003eLANGUAGE SQL\u003c/code\u003e函数的主体，SQL 标准只规定了\u003cem\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e形式。\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/div\u003e\u003cp\u003e简单的\u003ccode\u003eLANGUAGE SQL\u003c/code\u003e函数可以写成既符合标准、又能移植到其他实现的形式。更复杂的函数若使用高级特性、优化属性或其他语言，就不可避免地在很大程度上是 PostgreSQL 特有的。\u003c/p\u003e\u003c/section\u003e\u003csection\u003e\u003ch2\u003e另见\u003c/h2\u003e\u003cspan\u003e\u003ca href=\"/wiki/sql/alter-function/?v=18\" title=\"ALTER FUNCTION\" rel=\"nofollow\"\u003e\u003cspan\u003eALTER FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/drop-function/?v=18\" title=\"DROP FUNCTION\" rel=\"nofollow\"\u003e\u003cspan\u003eDROP FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/grant/?v=18\" title=\"GRANT\" rel=\"nofollow\"\u003e\u003cspan\u003eGRANT\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/load/?v=18\" title=\"LOAD\" rel=\"nofollow\"\u003e\u003cspan\u003eLOAD\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/revoke/?v=18\" title=\"REVOKE\" rel=\"nofollow\"\u003e\u003cspan\u003eREVOKE\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e\u003c/section\u003e","SourceRevision":"1b5ca64c","ContentHash":"25da32c5cf5d26cf84305859bfc39366a64041f91b6bda4affb9327486a904c8","Payload":{"purpose_zh":"定义一个新函数","sections":[{"html":"\u003cp\u003e\u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e定义一个新函数。\u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e将创建一个新函数，或者替换现有定义。要定义函数，用户必须具有该语言上的\u003ccode class=\"literal\"\u003eUSAGE\u003c/code\u003e权限。\u003c/p\u003e\u003cp\u003e如果包含模式名，那么该函数会被创建在指定的模式中。否则，它会被创建在当前模式中。新函数的名称不能匹配同一模式中任何具有相同输入参数类型的现有函数或过程。不过，不同参数类型的函数和过程能够共享一个名字（这被称为\u003cem class=\"firstterm\"\u003e重载\u003c/em\u003e）。\u003c/p\u003e\u003cp\u003e要替换一个现有函数的当前定义，可以使用\u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e。但不能用这种方式更改函数的名称或者参数类型（如果尝试这样做，实际上就会创建一个新的不同函数）。此外，\u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e也不允许更改现有函数的返回类型。要做到这一点，必须删除该函数并重新创建。（使用\u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e参数时，这意味着除非删除该函数，否则不能更改任何\u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e参数的类型。）\u003c/p\u003e\u003cp\u003e当\u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e被用来替换一个现有函数时，该函数的拥有权和权限不会改变。所有其他的函数属性会按照该命令中指定的或者隐含的值赋值。必须拥有（包括成为拥有角色的成员）该函数才能替换它。\u003c/p\u003e\u003cp\u003e如果删除函数后再重新创建，新函数就不再是旧函数的同一实体；你将必须删除引用旧函数的现有规则、视图、触发器等。使用\u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e可以在不破坏引用该函数的对象的情况下更改函数定义。此外，\u003ccode class=\"command\"\u003eALTER FUNCTION\u003c/code\u003e还可用于更改现有函数的大多数辅助属性。\u003c/p\u003e\u003cp\u003e创建该函数的用户将成为该函数的拥有者。\u003c/p\u003e\u003cp\u003e要创建一个函数，你必须拥有参数类型和返回类型上的\u003ccode class=\"literal\"\u003eUSAGE\u003c/code\u003e权限。\u003c/p\u003e\u003cp\u003e有关编写函数的详细信息，请参阅\u003ca href=\"/docs/18/xfunc.html\" title=\"36.3. 用户定义的函数\"\u003e第 36.3 节\u003c/a\u003e。\u003c/p\u003e","key":"description","title":"描述"},{"html":"\u003cdiv class=\"variablelist\"\u003e\u003cdl class=\"variablelist\"\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e要创建的函数名称（可以被模式限定）。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eargmode\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e参数的模式可以是：\u003ccode class=\"literal\"\u003eIN\u003c/code\u003e、\u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e、\u003ccode class=\"literal\"\u003eINOUT\u003c/code\u003e或者\u003ccode class=\"literal\"\u003eVARIADIC\u003c/code\u003e。如果省略，则默认为\u003ccode class=\"literal\"\u003eIN\u003c/code\u003e。只有\u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e参数可以跟在\u003ccode class=\"literal\"\u003eVARIADIC\u003c/code\u003e参数之后。此外，\u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e和\u003ccode class=\"literal\"\u003eINOUT\u003c/code\u003e参数不能与\u003ccode class=\"literal\"\u003eRETURNS TABLE\u003c/code\u003e记法一起使用。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eargname\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e参数的名称。某些语言（包括 SQL 和 PL/pgSQL）允许在函数体中使用该名称。对于其他语言，就函数本身而言，输入参数的名称只是额外文档；但你可以在调用函数时使用输入参数名来提高可读性（见\u003ca href=\"/docs/18/sql-syntax-calling-funcs.html\" title=\"4.3. 调用函数\"\u003e第 4.3 节\u003c/a\u003e）。无论如何，输出参数的名称很重要，因为它定义了结果行类型中的列名。（如果省略输出参数的名称，系统将选择一个默认列名。）\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eargtype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该函数参数（如果有）的数据类型（可以是模式限定的）。参数类型可以是基础类型、复合类型或者域类型，也可以引用一个表列的类型。\u003c/p\u003e\u003cp\u003e根据实现语言的不同，也可能允许指定诸如\u003ccode class=\"type\"\u003ecstring\u003c/code\u003e这样的\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e伪类型\u003c/span\u003e”\u003c/span\u003e。伪类型表示实际参数类型要么没有被完整指定，要么不属于普通 SQL 数据类型集合。\u003c/p\u003e\u003cp\u003e写成\u003ccode class=\"literal\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003etable_name\u003c/code\u003e\u003c/em\u003e.\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e%TYPE\u003c/code\u003e即可引用一个列的类型。使用这种特性有时有助于让函数独立于表定义的变化。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefault_expr\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e如果未指定该参数，则用作默认值的表达式。该表达式必须能被强制转换为该参数的类型。只有输入参数（包括\u003ccode class=\"literal\"\u003eINOUT\u003c/code\u003e）才能有默认值。所有跟在具有默认值参数之后的输入参数也都必须有默认值。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003erettype\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e该函数的返回数据类型（可以是模式限定的）。返回类型可以是基础类型、复合类型或者域类型，也可以引用一个表列的类型。根据实现语言的不同，也可能允许指定诸如\u003ccode class=\"type\"\u003ecstring\u003c/code\u003e这样的\u003cspan class=\"quote\"\u003e“\u003cspan class=\"quote\"\u003e伪类型\u003c/span\u003e”\u003c/span\u003e。如果函数不应该返回值，请把返回类型指定为\u003ccode class=\"type\"\u003evoid\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e当存在\u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e或\u003ccode class=\"literal\"\u003eINOUT\u003c/code\u003e参数时，可以省略\u003ccode class=\"literal\"\u003eRETURNS\u003c/code\u003e子句。如果写出该子句，它必须与输出参数所隐含的结果类型一致：如果有多个输出参数，则为\u003ccode class=\"literal\"\u003eRECORD\u003c/code\u003e；如果只有一个输出参数，则为该输出参数的类型。\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eSETOF\u003c/code\u003e修饰符表示该函数将返回一组项，而不是单个项。\u003c/p\u003e\u003cp\u003e写成\u003ccode class=\"literal\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003etable_name\u003c/code\u003e\u003c/em\u003e.\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e%TYPE\u003c/code\u003e即可引用一个列的类型。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eRETURNS TABLE\u003c/code\u003e语法中输出列的名称。这实际上是声明一个具名\u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e参数的另一种方式，只不过\u003ccode class=\"literal\"\u003eRETURNS TABLE\u003c/code\u003e还隐含了\u003ccode class=\"literal\"\u003eRETURNS SETOF\u003c/code\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_type\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eRETURNS TABLE\u003c/code\u003e语法中的输出列的数据类型。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003elang_name\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e用以实现该函数的语言的名称。可以是\u003ccode class=\"literal\"\u003esql\u003c/code\u003e、\u003ccode class=\"literal\"\u003ec\u003c/code\u003e、\u003ccode class=\"literal\"\u003einternal\u003c/code\u003e或者一个用户定义的过程语言的名称，例如\u003ccode class=\"literal\"\u003eplpgsql\u003c/code\u003e。如果指定了\u003cem class=\"replaceable\"\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e，则默认值为\u003ccode class=\"literal\"\u003esql\u003c/code\u003e。使用单引号将名称括起来已废弃，并要求大小写匹配。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eTRANSFORM { FOR TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_name\u003c/code\u003e\u003c/em\u003e } [, ... ] }\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e列出调用该函数时应应用的转换。转换在 SQL 类型和语言相关的数据类型之间进行变换，详见\u003ca href=\"/docs/18/sql-createtransform.html\" title=\"CREATE TRANSFORM\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE TRANSFORM\u003c/span\u003e\u003c/a\u003e。过程语言实现通常把有关内置类型的知识硬编码在代码中，因此那些不需要列举在这里。如果一种过程语言实现不知道如何处理某种类型且没有提供转换，它将回退到默认的数据类型转换行为，但这取决于具体实现。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eWINDOW\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eWINDOW\u003c/code\u003e表示该函数是\u003cem class=\"firstterm\"\u003e窗口函数\u003c/em\u003e而不是普通函数。目前这只对用 C 编写的函数有用。在替换现有函数定义时，不能更改\u003ccode class=\"literal\"\u003eWINDOW\u003c/code\u003e属性。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eIMMUTABLE\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eSTABLE\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eVOLATILE\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e这些属性会告诉查询优化器该函数的行为。最多只能指定其中一个。如果这些属性都没有出现，则默认假定为\u003ccode class=\"literal\"\u003eVOLATILE\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eIMMUTABLE\u003c/code\u003e表示该函数不能修改数据库，并且在给定相同参数值时总会返回相同结果；也就是说，它不会执行数据库查找，也不会以其他方式使用未直接出现在其参数列表中的信息。如果给出此选项，任何使用全常量参数对该函数的调用都可以立即替换为该函数值。\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eSTABLE\u003c/code\u003e表示该函数不能修改数据库，并且在一次表扫描内，对于相同参数值会一致地返回相同结果，但其结果可能在不同 SQL 语句之间发生变化。这适用于结果依赖于数据库查找、参数变量（例如当前时区）等的函数。（对于希望查询由当前命令修改过的行的\u003ccode class=\"literal\"\u003eAFTER\u003c/code\u003e触发器，这样做并不合适。）另请注意，\u003ccode class=\"function\"\u003ecurrent_timestamp\u003c/code\u003e函数族也属于稳定函数，因为它们的值在一个事务内不会变化。\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eVOLATILE\u003c/code\u003e表示该函数的值即使在一次表扫描内也可能发生变化，因此无法进行任何优化。从这个意义上说，真正不稳定的数据库函数相对较少；一些例子是\u003ccode class=\"literal\"\u003erandom()\u003c/code\u003e、\u003ccode class=\"literal\"\u003ecurrval()\u003c/code\u003e、\u003ccode class=\"literal\"\u003etimeofday()\u003c/code\u003e。但请注意，任何有副作用的函数都必须归类为不稳定，即使其结果相当可预测，也必须如此，以防其调用被优化掉；例如\u003ccode class=\"literal\"\u003esetval()\u003c/code\u003e。\u003c/p\u003e\u003cp\u003e更多细节见\u003ca href=\"/docs/18/xfunc-volatility.html\" title=\"36.7. 函数易变性分类\"\u003e第 36.7 节\u003c/a\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eLEAKPROOF\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eLEAKPROOF\u003c/code\u003e表示该函数没有副作用。除返回值外，它不会泄露其参数的任何信息。例如，对某些参数值会抛出错误而对另一些不会，或者在错误消息中包含参数值的函数，都不是防泄漏的。这会影响系统如何执行针对使用\u003ccode class=\"literal\"\u003esecurity_barrier\u003c/code\u003e选项创建的视图或启用了行级安全的表的查询。为了防止数据被无意暴露，系统会先强制执行安全策略和安全屏障视图中的条件，再执行查询本身中包含非防泄漏函数的用户提供条件。被标记为防泄漏的函数和操作符被视为可信，因此可以在安全策略和安全屏障视图的条件之前执行。此外，不接受参数的函数，或者没有从安全屏障视图或表中接收到任何参数的函数，即使未标记为防泄漏，也可以在安全条件之前执行。参见\u003ca href=\"/docs/18/sql-createview.html\" title=\"CREATE VIEW\"\u003e\u003cspan class=\"refentrytitle\"\u003eCREATE VIEW\u003c/span\u003e\u003c/a\u003e和\u003ca href=\"/docs/18/rules-privileges.html\" title=\"39.5. 规则和权限\"\u003e第 39.5 节\u003c/a\u003e。此选项只能由超级用户设置。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eCALLED ON NULL INPUT\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eSTRICT\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eCALLED ON NULL INPUT\u003c/code\u003e（默认）表示当某些参数为空值时，仍会正常调用该函数。如果有需要，则由函数作者负责检查空值并作出适当响应。\u003c/p\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e或\u003ccode class=\"literal\"\u003eSTRICT\u003c/code\u003e表示只要任一参数为空值，该函数总是返回空值。如果指定了这个选项，那么在参数中出现空值时不会执行该函数，而是自动假定结果为空值。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003e[\u003cspan class=\"optional\"\u003eEXTERNAL\u003c/span\u003e] SECURITY INVOKER\u003c/code\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003e[\u003cspan class=\"optional\"\u003eEXTERNAL\u003c/span\u003e] SECURITY DEFINER\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eSECURITY INVOKER\u003c/code\u003e表示要以调用它的用户的权限来执行该函数。这是默认值。\u003ccode class=\"literal\"\u003eSECURITY DEFINER\u003c/code\u003e指定要以拥有它的用户的权限来执行该函数。有关如何安全地编写\u003ccode class=\"literal\"\u003eSECURITY DEFINER\u003c/code\u003e函数的信息，见\u003ca href=\"/docs/18/sql-createfunction.html#SQL-CREATEFUNCTION-SECURITY\" title=\"安全地编写 SECURITY DEFINER函数\"\u003e下文\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e为了符合 SQL，允许使用关键字\u003ccode class=\"literal\"\u003eEXTERNAL\u003c/code\u003e。但它是可选的，因为与 SQL 不同，这个特性适用于所有函数，而不仅仅是外部函数。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003ePARALLEL\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003ePARALLEL UNSAFE\u003c/code\u003e表示该函数不能在并行模式中执行；SQL 语句中只要出现这类函数就会强制使用串行执行计划。这是默认选项。\u003ccode class=\"literal\"\u003ePARALLEL RESTRICTED\u003c/code\u003e表示该函数可以在并行模式中执行，但只能在并行组领导者进程中执行。\u003ccode class=\"literal\"\u003ePARALLEL SAFE\u003c/code\u003e表示该函数可以在并行模式下不受限制地执行，包括在并行工作进程中执行。\u003c/p\u003e\u003cp\u003e如果函数会修改任何数据库状态、改变事务状态（使用子事务进行错误恢复除外）、访问序列（例如调用\u003ccode class=\"literal\"\u003ecurrval\u003c/code\u003e），或者对设置做持久性更改，则应标记为并行不安全。如果函数访问临时表、客户端连接状态、游标、预备语句，或者系统无法在并行模式下同步的其他后端本地状态，则应标记为并行受限（例如，\u003ccode class=\"literal\"\u003esetseed\u003c/code\u003e只能由组领导者执行，因为其他进程所做的更改不会反映到领导者中）。一般来说，如果函数实际上是受限或不安全却被标记为安全，或者实际上不安全却被标记为受限，那么在并行查询中使用它时可能会抛出错误或产生错误结果。C 语言函数若被错误标记，理论上甚至可能表现出完全未定义的行为，因为系统无法保护自己不受任意 C 代码的影响；不过在大多数情况下，结果通常也不会比其他函数更糟。如果拿不准，函数就应标记为\u003ccode class=\"literal\"\u003eUNSAFE\u003c/code\u003e，这也是默认值。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eCOST\u003c/code\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003eexecution_cost\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e一个正数，给出该函数的估计执行代价，单位为\u003ca href=\"/docs/18/runtime-config-query.html#GUC-CPU-OPERATOR-COST\"\u003ecpu_operator_cost\u003c/a\u003e。如果该函数返回一个集合，则这是每个返回行的代价。如果未指定代价，则对 C 语言和内部函数假定为 1 个单位，对其他所有语言的函数假定为 100 个单位。较大的值会让规划器尽量避免对该函数进行不必要的频繁求值。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eROWS\u003c/code\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003eresult_rows\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e一个正数，给出规划器应预计该函数返回的行数。只有函数被声明为返回集合时才允许使用此项。默认假定为 1000 行。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003eSUPPORT\u003c/code\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003esupport_function\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e用于此函数的\u003cem class=\"firstterm\"\u003e规划器支持函数\u003c/em\u003e的名称（可选模式限定）。详见\u003ca href=\"/docs/18/xfunc-optimization.html\" title=\"36.11. 函数优化信息\"\u003e第 36.11 节\u003c/a\u003e。使用此选项必须是超级用户。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003econfiguration_parameter\u003c/code\u003e\u003c/em\u003e\u003cbr\u003e\u003c/span\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003evalue\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eSET\u003c/code\u003e子句会在进入函数时将指定的配置参数设为给定值，并在函数退出时恢复为先前的值。\u003ccode class=\"literal\"\u003eSET FROM CURRENT\u003c/code\u003e会把执行\u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e时该参数的当前值保存下来，作为进入函数时要应用的值。\u003c/p\u003e\u003cp\u003e如果函数附带了\u003ccode class=\"literal\"\u003eSET\u003c/code\u003e子句，那么在函数内针对同一变量执行的\u003ccode class=\"command\"\u003eSET LOCAL\u003c/code\u003e命令，其效果会被限制在该函数内部：函数退出时，配置参数先前的值仍会被恢复。不过，普通的\u003ccode class=\"command\"\u003eSET\u003c/code\u003e命令（不带\u003ccode class=\"literal\"\u003eLOCAL\u003c/code\u003e）会覆盖\u003ccode class=\"literal\"\u003eSET\u003c/code\u003e子句，就像它会覆盖先前的\u003ccode class=\"command\"\u003eSET LOCAL\u003c/code\u003e命令一样：这类命令的效果会在函数退出后继续保持，除非当前事务被回滚。\u003c/p\u003e\u003cp\u003e关于允许的参数名和值的更多信息，见\u003ca href=\"/docs/18/sql-set.html\" title=\"SET\"\u003e\u003cspan class=\"refentrytitle\"\u003eSET\u003c/span\u003e\u003c/a\u003e和\u003ca href=\"/docs/18/runtime-config.html\" title=\"第 19 章 服务器配置\"\u003e第 19 章\u003c/a\u003e。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefinition\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e一个定义该函数的字符串常量，其含义取决于所用语言。它可以是一个内部函数名称、一个对象文件的路径、一个 SQL 命令，或者用一种过程语言编写的文本。\u003c/p\u003e\u003cp\u003e使用美元引用（见\u003ca href=\"/docs/18/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING\" title=\"4.1.2.4. 美元引用的字符串常量\"\u003e第 4.1.2.4 节\u003c/a\u003e）来书写函数定义字符串通常会更有帮助，而不是使用普通的单引号语法。如果没有美元引用，函数定义中的任何单引号或者反斜线都必须用双写来转义。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003ccode class=\"literal\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003eobj_file\u003c/code\u003e\u003c/em\u003e, \u003cem class=\"replaceable\"\u003e\u003ccode\u003elink_symbol\u003c/code\u003e\u003c/em\u003e\u003c/code\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e当 C 语言源代码中的函数名与 SQL 函数的名称不同时，这种形式的\u003ccode class=\"literal\"\u003eAS\u003c/code\u003e子句用于动态可加载的 C 语言函数。字符串\u003cem class=\"replaceable\"\u003e\u003ccode\u003eobj_file\u003c/code\u003e\u003c/em\u003e是包含已编译 C 函数的共享库文件名，其解释方式与\u003ca href=\"/docs/18/sql-load.html\" title=\"LOAD\"\u003e\u003ccode class=\"command\"\u003eLOAD\u003c/code\u003e\u003c/a\u003e命令相同。字符串\u003cem class=\"replaceable\"\u003e\u003ccode\u003elink_symbol\u003c/code\u003e\u003c/em\u003e是该函数的链接符号，也就是该函数在 C 语言源代码中的名称。如果省略链接符号，则假定它与正在定义的 SQL 函数名称相同。所有函数的 C 名称都必须不同，因此必须为重载的 C 函数指定不同的 C 名称（例如把参数类型作为 C 名称的一部分）。\u003c/p\u003e\u003cp\u003e当重复的\u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e调用引用同一个对象文件时，该文件在每个会话中只装载一次。要卸载并重新装载该文件（例如在开发期间），请启动一个新会话。\u003c/p\u003e\u003c/dd\u003e\u003cdt\u003e\u003cspan class=\"term\"\u003e\u003cem class=\"replaceable\"\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e\u003c/span\u003e\u003c/dt\u003e\u003cdd\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eLANGUAGE SQL\u003c/code\u003e函数的主体。它可以是单个语句\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eRETURN \u003cem class=\"replaceable\"\u003e\u003ccode\u003eexpression\u003c/code\u003e\u003c/em\u003e\n\u003c/pre\u003e\u003cp\u003e或者一个语句块\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eBEGIN ATOMIC\n  \u003cem class=\"replaceable\"\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\n  \u003cem class=\"replaceable\"\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\n  ...\n  \u003cem class=\"replaceable\"\u003e\u003ccode\u003estatement\u003c/code\u003e\u003c/em\u003e;\nEND\n\u003c/pre\u003e\u003cp\u003e这类似于将函数体的文本写成字符串常量（见上面的\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefinition\u003c/code\u003e\u003c/em\u003e），但有一些不同：此形式仅适用于\u003ccode class=\"literal\"\u003eLANGUAGE SQL\u003c/code\u003e，字符串常量形式适用于所有语言。此形式在函数定义时解析，字符串常量形式在执行时解析；因此，此形式不能支持多态参数类型以及其他在函数定义时无法解析的构造。此形式跟踪函数和函数体中使用的对象之间的依赖关系，因此 \u003ccode class=\"literal\"\u003eDROP ... CASCADE\u003c/code\u003e将正常工作，而使用字符串文本的形式可能会留下悬空函数。最后，此形式与 SQL 标准和其他 SQL 实现更加兼容。\u003c/p\u003e\u003c/dd\u003e\u003c/dl\u003e\u003c/div\u003e","key":"parameters","title":"参数"},{"html":"\u003cp\u003e\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e允许函数\u003cem class=\"firstterm\"\u003e重载\u003c/em\u003e；也就是说，只要输入参数类型不同，同一个名称就可以用于多个不同的函数。无论你是否使用这一能力，在某些用户不信任其他用户的数据库中调用函数时，都需要采取安全预防措施；参见\u003ca href=\"/docs/18/typeconv-func.html\" title=\"10.3. 函数\"\u003e第 10.3 节\u003c/a\u003e。\u003c/p\u003e\u003cp\u003e如果两个函数具有相同的名称和\u003cspan class=\"emphasis\"\u003e\u003cem\u003e输入\u003c/em\u003e\u003c/span\u003e参数类型，它们被认为相同（不考虑任何\u003ccode class=\"literal\"\u003eOUT\u003c/code\u003e参数）。因此这些声明会冲突：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION foo(int) ...\nCREATE FUNCTION foo(int, out text) ...\n\u003c/pre\u003e\u003cp\u003e参数类型列表不同的函数在创建时不会被视为冲突，但如果提供了默认值，则在使用时可能发生冲突。例如，考虑下面这些声明：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION foo(int) ...\nCREATE FUNCTION foo(int, int default 42) ...\n\u003c/pre\u003e\u003cp\u003e调用\u003ccode class=\"literal\"\u003efoo(10)\u003c/code\u003e会失败，因为系统无法确定应该调用哪个函数。\u003c/p\u003e","key":"other","title":"重载"},{"html":"\u003cp\u003e允许使用完整的\u003cacronym\u003eSQL\u003c/acronym\u003e类型语法来声明函数参数和返回值。不过，\u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e会丢弃带圆括号的类型修饰符（例如\u003ccode class=\"type\"\u003enumeric\u003c/code\u003e类型的精度字段）。因此，\u003ccode class=\"literal\"\u003eCREATE FUNCTION foo (varchar(10)) ...\u003c/code\u003e与\u003ccode class=\"literal\"\u003eCREATE FUNCTION foo (varchar) ...\u003c/code\u003e完全等同。\u003c/p\u003e\u003cp\u003e在用\u003ccode class=\"command\"\u003eCREATE OR REPLACE FUNCTION\u003c/code\u003e替换现有函数时，更改参数名会受到限制。不能更改已经分配给任何输入参数的名称（但可以给先前没有名称的参数补上名称）。如果输出参数多于一个，也不能更改输出参数的名称，因为那会改变描述函数结果的匿名复合类型的列名。这些限制是为了确保函数被替换时，已有的函数调用不会停止工作。\u003c/p\u003e\u003cp\u003e如果一个函数被声明为带有\u003ccode class=\"literal\"\u003eVARIADIC\u003c/code\u003e参数的\u003ccode class=\"literal\"\u003eSTRICT\u003c/code\u003e函数，则严格性检查测试的是可变参数数组\u003cspan class=\"emphasis\"\u003e\u003cem\u003e作为一个整体\u003c/em\u003e\u003c/span\u003e是否非空。如果该数组包含空值元素，仍会调用该函数。\u003c/p\u003e","key":"notes","title":"注解"},{"html":"\u003cp\u003e使用 SQL 函数把两个整数相加：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION add(integer, integer) RETURNS integer\n    AS 'select $1 + $2;'\n    LANGUAGE SQL\n    IMMUTABLE\n    RETURNS NULL ON NULL INPUT;\n\u003c/pre\u003e\u003cp\u003e同一函数也可以用更符合 SQL 标准的风格来编写，使用参数名和不加引号的函数体：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION add(a integer, b integer) RETURNS integer\n    LANGUAGE SQL\n    IMMUTABLE\n    RETURNS NULL ON NULL INPUT\n    RETURN a + b;\n\u003c/pre\u003e\u003cp\u003e在\u003cspan class=\"application\"\u003ePL/pgSQL\u003c/span\u003e中，使用参数名把一个整数加 1：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE OR REPLACE FUNCTION increment(i integer) RETURNS integer AS $$\n        BEGIN\n                RETURN i + 1;\n        END;\n$$ LANGUAGE plpgsql;\n\u003c/pre\u003e\u003cp\u003e返回一个包含多个输出参数的记录：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION dup(in int, out f1 int, out f2 text)\n    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003e你也可以用一个显式命名的复合类型，更详细地表达同样的意思：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE TYPE dup_result AS (f1 int, f2 text);\n\nCREATE FUNCTION dup(int) RETURNS dup_result\n    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003e另一种返回多列的方法是使用\u003ccode class=\"literal\"\u003eTABLE\u003c/code\u003e函数：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION dup(int) RETURNS TABLE(f1 int, f2 text)\n    AS $$ SELECT $1, CAST($1 AS text) || ' is text' $$\n    LANGUAGE SQL;\n\nSELECT * FROM dup(42);\n\u003c/pre\u003e\u003cp\u003e不过，\u003ccode class=\"literal\"\u003eTABLE\u003c/code\u003e函数与前面的示例不同，因为它实际返回的是一\u003cspan class=\"emphasis\"\u003e\u003cem\u003e组\u003c/em\u003e\u003c/span\u003e记录，而不只是单条记录。\u003c/p\u003e","key":"examples","title":"示例"},{"html":"\u003cp\u003e因为\u003ccode class=\"literal\"\u003eSECURITY DEFINER\u003c/code\u003e函数要以拥有它的用户的权限执行，所以必须小心确保该函数不会被滥用。出于安全考虑，应将\u003ca href=\"/docs/18/runtime-config-client.html#GUC-SEARCH-PATH\"\u003esearch_path\u003c/a\u003e设置为排除任何可被不受信任用户写入的模式。这可以防止恶意用户创建对象（例如表、函数和操作符）来遮蔽该函数原本打算使用的对象。在这方面尤其重要的是临时表模式；默认情况下它最先被搜索，而且通常任何人都可写。一个安全的安排是强制把临时模式放到搜索顺序的最后。要做到这一点，应把\u003ccode class=\"literal\"\u003epg_temp\u003c/code\u003e写成\u003ccode class=\"varname\"\u003esearch_path\u003c/code\u003e中的最后一项。下面这个函数展示了安全用法：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eCREATE FUNCTION check_password(uname TEXT, pass TEXT)\nRETURNS BOOLEAN AS $$\nDECLARE passed BOOLEAN;\nBEGIN\n        SELECT  (pwd = $2) INTO passed\n        FROM    pwds\n        WHERE   username = $1;\n\n        RETURN passed;\nEND;\n$$  LANGUAGE plpgsql\n    SECURITY DEFINER\n    -- 设置一个安全的 search_path：受信的模式，然后是 'pg_temp'。\n    SET search_path = admin, pg_temp;\n\u003c/pre\u003e\u003cp\u003e这个函数的意图是访问\u003ccode class=\"literal\"\u003eadmin.pwds\u003c/code\u003e表。但如果没有\u003ccode class=\"literal\"\u003eSET\u003c/code\u003e子句，或者\u003ccode class=\"literal\"\u003eSET\u003c/code\u003e子句只提到\u003ccode class=\"literal\"\u003eadmin\u003c/code\u003e，那么该函数就可能因为有人创建一个名为\u003ccode class=\"literal\"\u003epwds\u003c/code\u003e的临时表而被利用。\u003c/p\u003e\u003cp\u003e如果该\u003ccode class=\"literal\"\u003eSECURITY DEFINER\u003c/code\u003e函数打算创建角色，并且以非超级用户身份运行，那么还应使用\u003ccode class=\"literal\"\u003eSET\u003c/code\u003e子句将\u003ccode class=\"varname\"\u003ecreaterole_self_grant\u003c/code\u003e设置为一个已知值。\u003c/p\u003e\u003cp\u003e另一点需要记住的是，默认情况下，新创建的函数会把执行权限授予\u003ccode class=\"literal\"\u003ePUBLIC\u003c/code\u003e（详见\u003ca href=\"/docs/18/ddl-priv.html\" title=\"5.8. 权限\"\u003e第 5.8 节\u003c/a\u003e）。通常你会希望只允许某些用户使用\u003ccode class=\"literal\"\u003eSECURITY DEFINER\u003c/code\u003e函数。要做到这一点，必须先撤销默认的\u003ccode class=\"literal\"\u003ePUBLIC\u003c/code\u003e权限，然后有选择地授予执行权限。为了避免新函数在一段时间窗口内对所有人都可访问，应在同一个事务中创建该函数并设置权限。例如：\u003c/p\u003e\u003cpre class=\"programlisting\"\u003eBEGIN;\nCREATE FUNCTION check_password(uname TEXT, pass TEXT) ... SECURITY DEFINER;\nREVOKE ALL ON FUNCTION check_password(uname TEXT, pass TEXT) FROM PUBLIC;\nGRANT EXECUTE ON FUNCTION check_password(uname TEXT, pass TEXT) TO admins;\nCOMMIT;\n\u003c/pre\u003e","key":"other","title":"安全地编写 SECURITY DEFINER函数"},{"html":"\u003cp\u003e\u003ccode class=\"command\"\u003eCREATE FUNCTION\u003c/code\u003e命令由 SQL 标准定义。\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e的实现可以按兼容方式使用，但也包含许多扩展。反过来，SQL 标准还规定了一些\u003cspan class=\"productname\"\u003ePostgreSQL\u003c/span\u003e尚未实现的可选特性。\u003c/p\u003e\u003cp\u003e以下是重要的兼容性问题：\u003c/p\u003e\u003cdiv class=\"itemizedlist\"\u003e\u003cul class=\"itemizedlist\"\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eOR REPLACE\u003c/code\u003e是 PostgreSQL 扩展。\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003e为与某些其他数据库系统兼容，\u003cem class=\"replaceable\"\u003e\u003ccode\u003eargmode\u003c/code\u003e\u003c/em\u003e可以写在\u003cem class=\"replaceable\"\u003e\u003ccode\u003eargname\u003c/code\u003e\u003c/em\u003e之前或之后，但只有前一种写法符合标准。\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003e对于参数默认值，SQL 标准只规定了带有\u003ccode class=\"literal\"\u003eDEFAULT\u003c/code\u003e关键字的语法。带\u003ccode class=\"literal\"\u003e=\u003c/code\u003e的语法用于 T-SQL 和 Firebird。\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003e\u003ccode class=\"literal\"\u003eSETOF\u003c/code\u003e修饰符是 PostgreSQL 扩展。\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003e只有\u003ccode class=\"literal\"\u003eSQL\u003c/code\u003e被标准化为一种语言。\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003e除\u003ccode class=\"literal\"\u003eCALLED ON NULL INPUT\u003c/code\u003e和\u003ccode class=\"literal\"\u003eRETURNS NULL ON NULL INPUT\u003c/code\u003e之外的所有其他属性都未标准化。\u003c/p\u003e\u003c/li\u003e\u003cli class=\"listitem\"\u003e\u003cp\u003e对于\u003ccode class=\"literal\"\u003eLANGUAGE SQL\u003c/code\u003e函数的主体，SQL 标准只规定了\u003cem class=\"replaceable\"\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e形式。\u003c/p\u003e\u003c/li\u003e\u003c/ul\u003e\u003c/div\u003e\u003cp\u003e简单的\u003ccode class=\"literal\"\u003eLANGUAGE SQL\u003c/code\u003e函数可以写成既符合标准、又能移植到其他实现的形式。更复杂的函数若使用高级特性、优化属性或其他语言，就不可避免地在很大程度上是 PostgreSQL 特有的。\u003c/p\u003e","key":"compatibility","title":"兼容性"},{"html":"\u003cspan class=\"simplelist\"\u003e\u003ca href=\"/wiki/sql/alter-function/?v=18\" title=\"ALTER FUNCTION\"\u003e\u003cspan class=\"refentrytitle\"\u003eALTER FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/drop-function/?v=18\" title=\"DROP FUNCTION\"\u003e\u003cspan class=\"refentrytitle\"\u003eDROP FUNCTION\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/grant/?v=18\" title=\"GRANT\"\u003e\u003cspan class=\"refentrytitle\"\u003eGRANT\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/load/?v=18\" title=\"LOAD\"\u003e\u003cspan class=\"refentrytitle\"\u003eLOAD\u003c/span\u003e\u003c/a\u003e, \u003ca href=\"/wiki/sql/revoke/?v=18\" title=\"REVOKE\"\u003e\u003cspan class=\"refentrytitle\"\u003eREVOKE\u003c/span\u003e\u003c/a\u003e\u003c/span\u003e","key":"see_also","title":"另见"}],"sections_same_as":"","synopsis_html":"CREATE [ OR REPLACE ] FUNCTION\n    \u003cem class=\"replaceable\"\u003e\u003ccode\u003ename\u003c/code\u003e\u003c/em\u003e ( [ [ \u003cem class=\"replaceable\"\u003e\u003ccode\u003eargmode\u003c/code\u003e\u003c/em\u003e ] [ \u003cem class=\"replaceable\"\u003e\u003ccode\u003eargname\u003c/code\u003e\u003c/em\u003e ] \u003cem class=\"replaceable\"\u003e\u003ccode\u003eargtype\u003c/code\u003e\u003c/em\u003e [ { DEFAULT | = } \u003cem class=\"replaceable\"\u003e\u003ccode\u003edefault_expr\u003c/code\u003e\u003c/em\u003e ] [, ...] ] )\n    [ RETURNS \u003cem class=\"replaceable\"\u003e\u003ccode\u003erettype\u003c/code\u003e\u003c/em\u003e\n      | RETURNS TABLE ( \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_name\u003c/code\u003e\u003c/em\u003e \u003cem class=\"replaceable\"\u003e\u003ccode\u003ecolumn_type\u003c/code\u003e\u003c/em\u003e [, ...] ) ]\n  { LANGUAGE \u003cem class=\"replaceable\"\u003e\u003ccode\u003elang_name\u003c/code\u003e\u003c/em\u003e\n    | TRANSFORM { FOR TYPE \u003cem class=\"replaceable\"\u003e\u003ccode\u003etype_name\u003c/code\u003e\u003c/em\u003e } [, ... ]\n    | WINDOW\n    | { IMMUTABLE | STABLE | VOLATILE }\n    | [ NOT ] LEAKPROOF\n    | { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }\n    | { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }\n    | PARALLEL { UNSAFE | RESTRICTED | SAFE }\n    | COST \u003cem class=\"replaceable\"\u003e\u003ccode\u003eexecution_cost\u003c/code\u003e\u003c/em\u003e\n    | ROWS \u003cem class=\"replaceable\"\u003e\u003ccode\u003eresult_rows\u003c/code\u003e\u003c/em\u003e\n    | SUPPORT \u003cem class=\"replaceable\"\u003e\u003ccode\u003esupport_function\u003c/code\u003e\u003c/em\u003e\n    | SET \u003cem class=\"replaceable\"\u003e\u003ccode\u003econfiguration_parameter\u003c/code\u003e\u003c/em\u003e { TO \u003cem class=\"replaceable\"\u003e\u003ccode\u003evalue\u003c/code\u003e\u003c/em\u003e | = \u003cem class=\"replaceable\"\u003e\u003ccode\u003evalue\u003c/code\u003e\u003c/em\u003e | FROM CURRENT }\n    | AS '\u003cem class=\"replaceable\"\u003e\u003ccode\u003edefinition\u003c/code\u003e\u003c/em\u003e'\n    | AS '\u003cem class=\"replaceable\"\u003e\u003ccode\u003eobj_file\u003c/code\u003e\u003c/em\u003e', '\u003cem class=\"replaceable\"\u003e\u003ccode\u003elink_symbol\u003c/code\u003e\u003c/em\u003e'\n    | \u003cem class=\"replaceable\"\u003e\u003ccode\u003esql_body\u003c/code\u003e\u003c/em\u003e\n  } ...","synopsis_text":"CREATE [ OR REPLACE ] FUNCTION\nname ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] )\n[ RETURNS rettype\n| RETURNS TABLE ( column_name column_type [, ...] ) ]\n{ LANGUAGE lang_name\n| TRANSFORM { FOR TYPE type_name } [, ... ]\n| WINDOW\n| { IMMUTABLE | STABLE | VOLATILE }\n| [ NOT ] LEAKPROOF\n| { CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT }\n| { [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER }\n| PARALLEL { UNSAFE | RESTRICTED | SAFE }\n| COST execution_cost\n| ROWS result_rows\n| SUPPORT support_function\n| SET configuration_parameter { TO value | = value | FROM CURRENT }\n| AS 'definition'\n| AS 'obj_file', 'link_symbol'\n| sql_body\n} ..."}},"RequestedLocale":"zh-Hans","Fallback":false,"Versions":["10","11","12","13","14","15","16","17","18","19","20","6.4","6.5","7.0","7.1","7.2","7.3","7.4","8.0","8.1","8.2","8.3","8.4","9.0","9.1","9.2","9.3","9.4","9.5","9.6"],"Locales":["en","zh-Hans"],"Signatures":null,"Spellings":null,"SQLState":null,"Evidence":null}
