Default values for function arguments

Pavel Stehule, with some tweaks by Peter Eisentraut
This commit is contained in:
Peter Eisentraut 2008-12-04 17:51:28 +00:00
parent 7b640b0345
commit 455dffbb73
29 changed files with 2848 additions and 2166 deletions

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.460 2008/11/14 00:51:46 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/func.sgml,v 1.461 2008/12/04 17:51:26 petere Exp $ -->
<chapter id="functions">
<title>Functions and Operators</title>
@ -11710,6 +11710,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<primary>pg_get_function_arguments</primary>
</indexterm>
<indexterm>
<primary>pg_get_function_identity_arguments</primary>
</indexterm>
<indexterm>
<primary>pg_get_function_result</primary>
</indexterm>
@ -11799,7 +11803,12 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
<row>
<entry><literal><function>pg_get_function_arguments</function>(<parameter>func_oid</parameter>)</literal></entry>
<entry><type>text</type></entry>
<entry>get argument list for function</entry>
<entry>get argument list of function's definition (with default values)</entry>
</row>
<row>
<entry><literal><function>pg_get_function_identity_arguments</function>(<parameter>func_oid</parameter>)</literal></entry>
<entry><type>text</type></entry>
<entry>get argument list to identify a function (without argument names, default values)</entry>
</row>
<row>
<entry><literal><function>pg_get_function_result</function>(<parameter>func_oid</parameter>)</literal></entry>
@ -11920,7 +11929,12 @@ SELECT pg_type_is_visible('myschema.widget'::regtype);
of a function, in the form it would need to appear in within
<command>CREATE FUNCTION</>.
<function>pg_get_function_result</function> similarly returns the
appropriate <literal>RETURNS</> clause for the function.
appropriate <literal>RETURNS</> clause for the function.
<function>pg_get_function_identity_arguments</function> returns the
argument list necessary to identify a function, in the form it
would need to appear in within <command>ALTER FUNCTION</>, for
instance. This form omits default values and argument names, for
example.
</para>
<para>

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.81 2008/11/14 10:22:46 petere Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.82 2008/12/04 17:51:26 petere Exp $
-->
<refentry id="SQL-CREATEFUNCTION">
@ -21,7 +21,7 @@ $PostgreSQL: pgsql/doc/src/sgml/ref/create_function.sgml,v 1.81 2008/11/14 10:22
<refsynopsisdiv>
<synopsis>
CREATE [ OR REPLACE ] FUNCTION
<replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [, ...] ] )
<replaceable class="parameter">name</replaceable> ( [ [ <replaceable class="parameter">argmode</replaceable> ] [ <replaceable class="parameter">argname</replaceable> ] <replaceable class="parameter">argtype</replaceable> [ { DEFAULT | = } <replaceable class="parameter">defexpr</replaceable>] [, ...] ] )
[ RETURNS <replaceable class="parameter">rettype</replaceable>
| RETURNS TABLE ( <replaceable class="parameter">colname</replaceable> <replaceable class="parameter">coltype</replaceable> [, ...] ) ]
{ LANGUAGE <replaceable class="parameter">langname</replaceable>
@ -154,6 +154,20 @@ CREATE [ OR REPLACE ] FUNCTION
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">defexpr</replaceable></term>
<listitem>
<para>
An expression to be used as default value if the parameter is
not specified. The expression has to be convertable to the
argument type of the parameter. All parameters after a
parameter with default value have to be parameters with default
values as well.
</para>
</listitem>
</varlistentry>
<varlistentry>
<term><replaceable class="parameter">rettype</replaceable></term>
@ -667,6 +681,14 @@ COMMIT;
either before or after <replaceable class="parameter">argname</replaceable>.
But only the first way is standard-compliant.
</para>
<para>
The SQL standard does not specify parameter defaults. The syntax
with the <literal>DEFAULT</literal> key word is from Oracle, and it
is somewhat in the spirit of the standard: SQL/PSM uses it for
variable default values. The syntax with <literal>=</literal> is
used in T-SQL and Firebird.
</para>
</refsect1>

View File

@ -1,4 +1,4 @@
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.133 2008/10/31 19:37:56 tgl Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/xfunc.sgml,v 1.134 2008/12/04 17:51:26 petere Exp $ -->
<sect1 id="xfunc">
<title>User-Defined Functions</title>
@ -663,6 +663,60 @@ SELECT mleast(VARIADIC ARRAY[10, -1, 5, 4.4]);
</para>
</sect2>
<sect2 id="xfunc-parameter-defaults">
<title><acronym>SQL</> Functions with Parameters Default Values</title>
<indexterm>
<primary>default values</primary>
</indexterm>
<para>
Functions can be declared with parameters with default values or
expressions. The default expressions are used as parameter value
if the parameter is not explicitly specified in a function call.
All parameters after a a parameter with default value have to be
parameters with default values as well.
</para>
<para>
For example:
<screen>
CREATE FUNCTION foo(a int DEFAULT 1, b int DEFAULT 2, c int DEFAULT 3)
RETURNS int
LANGUAGE SQL
AS $$
SELECT $1 + $2 + $3;
$$;
SELECT foo(10, 20, 30);
foo
-----
60
(1 row)
SELECT foo(10, 20);
foo
-----
33
(1 row)
SELECT foo(10);
foo
-----
15
(1 row)
SELECT foo();
foo
-----
6
(1 row)
</screen>
Instead of the key word <literal>DEFAULT</literal>,
the <literal>=</literal> sign can also be used.
</para>
</sect2>
<sect2 id="xfunc-sql-table-functions">
<title><acronym>SQL</acronym> Functions as Table Sources</title>

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.112 2008/09/09 18:58:08 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/namespace.c,v 1.113 2008/12/04 17:51:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -571,6 +571,11 @@ TypeIsVisible(Oid typid)
* If expand_variadic is false, variadic arguments are not treated specially,
* and the returned nvargs will always be zero.
*
* If expand_variadic is true, functions with argument default values
* will also be retrieved. If expand_variadic is false, default
* values will not be taken into account and functions that do not
* have exactly nargs arguments in total will not be considered.
*
* We search a single namespace if the function name is qualified, else
* all namespaces in the search path. The return list will never contain
* multiple entries with identical argument lists --- in the multiple-
@ -621,13 +626,45 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
int pathpos = 0;
bool variadic;
Oid va_elem_type;
List *defaults = NIL;
FuncCandidateList newResult;
/*
* Check if function has some parameter defaults if some
* parameters are missing.
*/
if (pronargs > nargs && expand_variadic)
{
bool isnull;
Datum proargdefaults;
char *str;
/* skip when not enough default expressions */
if (nargs + procform->pronargdefaults < pronargs)
continue;
proargdefaults = SysCacheGetAttr(PROCOID, proctup,
Anum_pg_proc_proargdefaults, &isnull);
Assert(!isnull);
str = TextDatumGetCString(proargdefaults);
defaults = (List *) stringToNode(str);
Assert(IsA(defaults, List));
/*
* If we don't have to use all default parameters, we skip
* some cells from the left.
*/
defaults = list_copy_tail(defaults, procform->pronargdefaults - pronargs + nargs);
pfree(str);
}
/*
* Check if function is variadic, and get variadic element type if so.
* If expand_variadic is false, we should just ignore variadic-ness.
*/
if (expand_variadic)
if (pronargs <= nargs && expand_variadic)
{
va_elem_type = procform->provariadic;
variadic = OidIsValid(va_elem_type);
@ -638,11 +675,16 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
variadic = false;
}
Assert(!variadic || !defaults);
/* Ignore if it doesn't match requested argument count */
if (nargs >= 0 &&
(variadic ? (pronargs > nargs) : (pronargs != nargs)))
(variadic ? (pronargs > nargs) : (defaults ? (pronargs < nargs) : (pronargs != nargs))))
continue;
Assert(!variadic || (pronargs <= nargs));
Assert(!defaults || (pronargs > nargs));
if (OidIsValid(namespaceId))
{
/* Consider only procs in specified namespace */
@ -681,6 +723,7 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
newResult->pathpos = pathpos;
newResult->oid = HeapTupleGetOid(proctup);
newResult->nargs = effective_nargs;
newResult->argdefaults = defaults;
memcpy(newResult->args, procform->proargtypes.values,
pronargs * sizeof(Oid));
if (variadic)
@ -695,6 +738,8 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
else
newResult->nvargs = 0;
any_variadic = variadic || defaults;
/*
* Does it have the same arguments as something we already accepted?
* If so, decide which one to keep. We can skip this check for the
@ -704,6 +749,9 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
*/
if (any_variadic || !OidIsValid(namespaceId))
{
if (defaults)
effective_nargs = nargs;
/*
* If we have an ordered list from SearchSysCacheList (the normal
* case), then any conflicting proc must immediately adjoin this
@ -733,11 +781,21 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
prevResult;
prevResult = prevResult->next)
{
if (effective_nargs == prevResult->nargs &&
memcmp(newResult->args,
prevResult->args,
effective_nargs * sizeof(Oid)) == 0)
if (!defaults)
{
if (effective_nargs == prevResult->nargs &&
memcmp(newResult->args,
prevResult->args,
effective_nargs * sizeof(Oid)) == 0)
break;
}
else
{
if (memcmp(newResult->args,
prevResult->args,
effective_nargs * sizeof(Oid)) == 0)
break;
}
}
}
if (prevResult)
@ -777,6 +835,20 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
pfree(newResult);
continue; /* keep previous result */
}
if (defaults)
{
if (prevResult->argdefaults != NIL)
ereport(ERROR,
(errcode(ERRCODE_AMBIGUOUS_FUNCTION),
errmsg("functions with parameter defaults %s and %s are ambiguous",
func_signature_string(names, pronargs, procform->proargtypes.values),
func_signature_string(names, prevResult->nargs, prevResult->args))));
/* else, previous result didn't have defaults */
pfree(newResult);
continue; /* keep previous result */
}
/* non-variadic can replace a previous variadic */
Assert(prevResult->nvargs > 0);
}
@ -784,6 +856,7 @@ FuncnameGetCandidates(List *names, int nargs, bool expand_variadic)
prevResult->pathpos = pathpos;
prevResult->oid = newResult->oid;
prevResult->nvargs = newResult->nvargs;
prevResult->argdefaults = newResult->argdefaults;
pfree(newResult);
continue; /* args are same, of course */
}

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.97 2008/11/14 19:47:50 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_aggregate.c,v 1.98 2008/12/04 17:51:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -229,7 +229,8 @@ AggregateCreate(const char *aggName,
PointerGetDatum(NULL), /* parameterNames */
PointerGetDatum(NULL), /* proconfig */
1, /* procost */
0); /* prorows */
0, /* prorows */
NULL); /* parameterDefaults */
/*
* Okay to create the pg_aggregate entry.
@ -321,7 +322,7 @@ lookup_agg_function(List *fnName,
*/
fdresult = func_get_detail(fnName, NIL, nargs, input_types, false,
&fnOid, rettype, &retset, &nvargs,
&true_oid_array);
&true_oid_array, NULL);
/* only valid case is a normal function not returning a set */
if (fdresult != FUNCDETAIL_NORMAL || !OidIsValid(fnOid))

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.154 2008/11/02 01:45:27 tgl Exp $
* $PostgreSQL: pgsql/src/backend/catalog/pg_proc.c,v 1.155 2008/12/04 17:51:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -75,7 +75,8 @@ ProcedureCreate(const char *procedureName,
Datum parameterNames,
Datum proconfig,
float4 procost,
float4 prorows)
float4 prorows,
List *parameterDefaults)
{
Oid retval;
int parameterCount;
@ -295,6 +296,7 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_proretset - 1] = BoolGetDatum(returnsSet);
values[Anum_pg_proc_provolatile - 1] = CharGetDatum(volatility);
values[Anum_pg_proc_pronargs - 1] = UInt16GetDatum(parameterCount);
values[Anum_pg_proc_pronargdefaults - 1] = UInt16GetDatum(list_length(parameterDefaults));
values[Anum_pg_proc_prorettype - 1] = ObjectIdGetDatum(returnType);
values[Anum_pg_proc_proargtypes - 1] = PointerGetDatum(parameterTypes);
if (allParameterTypes != PointerGetDatum(NULL))
@ -309,6 +311,13 @@ ProcedureCreate(const char *procedureName,
values[Anum_pg_proc_proargnames - 1] = parameterNames;
else
nulls[Anum_pg_proc_proargnames - 1] = true;
if (parameterDefaults != PointerGetDatum(NULL))
{
Assert(list_length(parameterDefaults) > 0);
values[Anum_pg_proc_proargdefaults - 1] = CStringGetTextDatum(nodeToString(parameterDefaults));
}
else
nulls[Anum_pg_proc_proargdefaults - 1] = true;
values[Anum_pg_proc_prosrc - 1] = CStringGetTextDatum(prosrc);
if (probin)
values[Anum_pg_proc_probin - 1] = CStringGetTextDatum(probin);

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.101 2008/11/02 01:45:27 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.102 2008/12/04 17:51:26 petere Exp $
*
* DESCRIPTION
* These routines take the parse tree and pick out the
@ -49,8 +49,10 @@
#include "commands/proclang.h"
#include "miscadmin.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_func.h"
#include "parser/parse_type.h"
#include "parser/parse_utilcmd.h"
#include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
@ -164,7 +166,9 @@ examine_parameter_list(List *parameters, Oid languageOid,
ArrayType **allParameterTypes,
ArrayType **parameterModes,
ArrayType **parameterNames,
Oid *requiredResultType)
List **parameterDefaults,
Oid *requiredResultType,
const char *queryString)
{
int parameterCount = list_length(parameters);
Oid *inTypes;
@ -177,6 +181,8 @@ examine_parameter_list(List *parameters, Oid languageOid,
bool have_names = false;
ListCell *x;
int i;
bool have_defaults = false;
ParseState *pstate;
*requiredResultType = InvalidOid; /* default result */
@ -184,6 +190,10 @@ examine_parameter_list(List *parameters, Oid languageOid,
allTypes = (Datum *) palloc(parameterCount * sizeof(Datum));
paramModes = (Datum *) palloc(parameterCount * sizeof(Datum));
paramNames = (Datum *) palloc0(parameterCount * sizeof(Datum));
*parameterDefaults = NIL;
pstate = make_parsestate(NULL);
pstate->p_sourcetext = queryString;
/* Scan the list and extract data into work arrays */
i = 0;
@ -276,9 +286,33 @@ examine_parameter_list(List *parameters, Oid languageOid,
have_names = true;
}
if (fp->defexpr)
{
if (fp->mode != FUNC_PARAM_IN && fp->mode != FUNC_PARAM_INOUT)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("only IN and INOUT parameters can have default values")));
*parameterDefaults = lappend(*parameterDefaults,
coerce_to_specific_type(NULL,
transformExpr(pstate, fp->defexpr),
toid,
"DEFAULT"));
have_defaults = true;
}
else
{
if (have_defaults)
ereport(ERROR,
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
errmsg("parameter without default value specified after parameter with default value")));
}
i++;
}
free_parsestate(pstate);
/* Now construct the proper outputs as needed */
*parameterTypes = buildoidvector(inTypes, inCount);
@ -653,7 +687,7 @@ interpret_AS_clause(Oid languageOid, const char *languageName,
* Execute a CREATE FUNCTION utility statement.
*/
void
CreateFunction(CreateFunctionStmt *stmt)
CreateFunction(CreateFunctionStmt *stmt, const char *queryString)
{
char *probin_str;
char *prosrc_str;
@ -680,6 +714,7 @@ CreateFunction(CreateFunctionStmt *stmt)
HeapTuple languageTuple;
Form_pg_language languageStruct;
List *as_clause;
List *defaults = NULL;
/* Convert list of names to a name and namespace */
namespaceId = QualifiedNameGetCreationNamespace(stmt->funcname,
@ -753,7 +788,9 @@ CreateFunction(CreateFunctionStmt *stmt)
&allParameterTypes,
&parameterModes,
&parameterNames,
&requiredResultType);
&defaults,
&requiredResultType,
queryString);
if (stmt->returnType)
{
@ -836,7 +873,8 @@ CreateFunction(CreateFunctionStmt *stmt)
PointerGetDatum(parameterNames),
PointerGetDatum(proconfig),
procost,
prorows);
prorows,
defaults);
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.80 2008/11/02 01:45:27 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/proclang.c,v 1.81 2008/12/04 17:51:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -149,7 +149,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
PointerGetDatum(NULL),
PointerGetDatum(NULL),
1,
0);
0,
NULL);
}
/*
@ -182,7 +183,8 @@ CreateProceduralLanguage(CreatePLangStmt *stmt)
PointerGetDatum(NULL),
PointerGetDatum(NULL),
1,
0);
0,
NULL);
}
}
else

View File

@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.414 2008/12/04 11:42:23 heikki Exp $
* $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.415 2008/12/04 17:51:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -2448,6 +2448,7 @@ _copyFunctionParameter(FunctionParameter *from)
COPY_STRING_FIELD(name);
COPY_NODE_FIELD(argType);
COPY_SCALAR_FIELD(mode);
COPY_NODE_FIELD(defexpr);
return newnode;
}

View File

@ -22,7 +22,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.339 2008/12/04 11:42:24 heikki Exp $
* $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.340 2008/12/04 17:51:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -1165,6 +1165,7 @@ _equalFunctionParameter(FunctionParameter *a, FunctionParameter *b)
COMPARE_STRING_FIELD(name);
COMPARE_NODE_FIELD(argType);
COMPARE_SCALAR_FIELD(mode);
COMPARE_NODE_FIELD(defexpr);
return true;
}

View File

@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.642 2008/12/04 11:42:24 heikki Exp $
* $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.643 2008/12/04 17:51:26 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@ -255,6 +255,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <list> stmtblock stmtmulti
OptTableElementList TableElementList OptInherit definition
OptWith opt_distinct opt_definition func_args func_args_list
func_args_with_defaults func_args_with_defaults_list
func_as createfunc_opt_list alterfunc_opt_list
aggr_args old_aggr_definition old_aggr_list
oper_argtypes RuleActionList RuleActionMulti
@ -278,7 +279,7 @@ static TypeName *TableFuncTypeName(List *columns);
%type <into> into_clause create_as_target
%type <defelt> createfunc_opt_item common_func_opt_item
%type <fun_param> func_arg table_func_column
%type <fun_param> func_arg func_arg_with_default table_func_column
%type <fun_param_mode> arg_class
%type <typnam> func_return func_type
@ -4170,7 +4171,7 @@ opt_nulls_order: NULLS_FIRST { $$ = SORTBY_NULLS_FIRST; }
*****************************************************************************/
CreateFunctionStmt:
CREATE opt_or_replace FUNCTION func_name func_args
CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
RETURNS func_return createfunc_opt_list opt_definition
{
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
@ -4182,7 +4183,7 @@ CreateFunctionStmt:
n->withClause = $9;
$$ = (Node *)n;
}
| CREATE opt_or_replace FUNCTION func_name func_args
| CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
RETURNS TABLE '(' table_func_column_list ')' createfunc_opt_list opt_definition
{
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
@ -4195,7 +4196,7 @@ CreateFunctionStmt:
n->withClause = $12;
$$ = (Node *)n;
}
| CREATE opt_or_replace FUNCTION func_name func_args
| CREATE opt_or_replace FUNCTION func_name func_args_with_defaults
createfunc_opt_list opt_definition
{
CreateFunctionStmt *n = makeNode(CreateFunctionStmt);
@ -4223,6 +4224,21 @@ func_args_list:
| func_args_list ',' func_arg { $$ = lappend($1, $3); }
;
/*
* func_args_with_defaults is separate because we only want to accept
* defaults in CREATE FUNCTION, not in ALTER etc.
*/
func_args_with_defaults:
'(' func_args_with_defaults_list ')' { $$ = $2; }
| '(' ')' { $$ = NIL; }
;
func_args_with_defaults_list:
func_arg_with_default { $$ = list_make1( $1); }
| func_args_with_defaults_list ',' func_arg_with_default { $$ = lappend($1, $3); }
;
/*
* The style with arg_class first is SQL99 standard, but Oracle puts
* param_name first; accept both since it's likely people will try both
@ -4240,6 +4256,7 @@ func_arg:
n->name = $2;
n->argType = $3;
n->mode = $1;
n->defexpr = NULL;
$$ = n;
}
| param_name arg_class func_type
@ -4248,6 +4265,7 @@ func_arg:
n->name = $1;
n->argType = $3;
n->mode = $2;
n->defexpr = NULL;
$$ = n;
}
| param_name func_type
@ -4256,6 +4274,7 @@ func_arg:
n->name = $1;
n->argType = $2;
n->mode = FUNC_PARAM_IN;
n->defexpr = NULL;
$$ = n;
}
| arg_class func_type
@ -4264,6 +4283,7 @@ func_arg:
n->name = NULL;
n->argType = $2;
n->mode = $1;
n->defexpr = NULL;
$$ = n;
}
| func_type
@ -4272,6 +4292,7 @@ func_arg:
n->name = NULL;
n->argType = $1;
n->mode = FUNC_PARAM_IN;
n->defexpr = NULL;
$$ = n;
}
;
@ -4322,6 +4343,23 @@ func_type: Typename { $$ = $1; }
}
;
func_arg_with_default:
func_arg
{
$$ = $1;
}
| func_arg DEFAULT a_expr
{
$$ = $1;
$$->defexpr = $3;
}
| func_arg '=' a_expr
{
$$ = $1;
$$->defexpr = $3;
}
;
createfunc_opt_list:
/* Must be at least one to prevent conflict */

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.207 2008/09/01 20:42:44 tgl Exp $
* $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.208 2008/12/04 17:51:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -77,6 +77,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
bool retset;
int nvargs;
FuncDetailCode fdresult;
List *argdefaults;
/*
* Most of the rest of the parser just assumes that functions do not have
@ -164,7 +165,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types,
!func_variadic,
&funcid, &rettype, &retset, &nvargs,
&declared_arg_types);
&declared_arg_types, &argdefaults);
if (fdresult == FUNCDETAIL_COERCION)
{
/*
@ -234,6 +235,21 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs,
parser_errposition(pstate, location)));
}
/* add stored expressions as called values for arguments with defaults */
if (argdefaults)
{
ListCell *lc;
foreach(lc, argdefaults)
{
Node *expr = (Node *) lfirst(lc);
fargs = lappend(fargs, expr);
actual_arg_types[nargs++] = exprType(expr);
}
}
/*
* enforce consistency with polymorphic argument and return types,
* possibly adjusting return type or declared_arg_types (which will be
@ -729,7 +745,8 @@ func_get_detail(List *funcname,
Oid *rettype, /* return value */
bool *retset, /* return value */
int *nvargs, /* return value */
Oid **true_typeids) /* return value */
Oid **true_typeids, /* return value */
List **argdefaults) /* return value */
{
FuncCandidateList raw_candidates;
FuncCandidateList best_candidate;
@ -870,6 +887,8 @@ func_get_detail(List *funcname,
*funcid = best_candidate->oid;
*nvargs = best_candidate->nvargs;
*true_typeids = best_candidate->args;
if (argdefaults)
*argdefaults = best_candidate->argdefaults;
ftup = SearchSysCache(PROCOID,
ObjectIdGetDatum(best_candidate->oid),

View File

@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.301 2008/11/07 18:25:06 tgl Exp $
* $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.302 2008/12/04 17:51:26 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -700,7 +700,7 @@ ProcessUtility(Node *parsetree,
break;
case T_CreateFunctionStmt: /* CREATE FUNCTION */
CreateFunction((CreateFunctionStmt *) parsetree);
CreateFunction((CreateFunctionStmt *) parsetree, queryString);
break;
case T_AlterFunctionStmt: /* ALTER FUNCTION */

View File

@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.287 2008/10/06 20:29:38 tgl Exp $
* $PostgreSQL: pgsql/src/backend/utils/adt/ruleutils.c,v 1.288 2008/12/04 17:51:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -141,7 +141,8 @@ static char *pg_get_constraintdef_worker(Oid constraintId, bool fullCommand,
static char *pg_get_expr_worker(text *expr, Oid relid, char *relname,
int prettyFlags);
static int print_function_arguments(StringInfo buf, HeapTuple proctup,
bool print_table_args);
bool print_table_args,
bool full);
static void print_function_rettype(StringInfo buf, HeapTuple proctup);
static void make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
int prettyFlags);
@ -1449,7 +1450,7 @@ pg_get_functiondef(PG_FUNCTION_ARGS)
nsp = get_namespace_name(proc->pronamespace);
appendStringInfo(&buf, "CREATE OR REPLACE FUNCTION %s(",
quote_qualified_identifier(nsp, name));
(void) print_function_arguments(&buf, proctup, false);
(void) print_function_arguments(&buf, proctup, false, true);
appendStringInfoString(&buf, ")\n RETURNS ");
print_function_rettype(&buf, proctup);
appendStringInfo(&buf, "\n LANGUAGE %s\n",
@ -1598,13 +1599,43 @@ pg_get_function_arguments(PG_FUNCTION_ARGS)
if (!HeapTupleIsValid(proctup))
elog(ERROR, "cache lookup failed for function %u", funcid);
(void) print_function_arguments(&buf, proctup, false);
(void) print_function_arguments(&buf, proctup, false, true);
ReleaseSysCache(proctup);
PG_RETURN_TEXT_P(string_to_text(buf.data));
}
/*
* pg_get_function_identity_arguments
* Get a formatted list of arguments for a function.
* This is everything that would go between the parentheses in
* ALTER FUNCTION, etc. skip names and defaults/
*/
Datum
pg_get_function_identity_arguments(PG_FUNCTION_ARGS)
{
Oid funcid = PG_GETARG_OID(0);
StringInfoData buf;
HeapTuple proctup;
initStringInfo(&buf);
proctup = SearchSysCache(PROCOID,
ObjectIdGetDatum(funcid),
0, 0, 0);
if (!HeapTupleIsValid(proctup))
elog(ERROR, "cache lookup failed for function %u", funcid);
(void) print_function_arguments(&buf, proctup, false, false);
ReleaseSysCache(proctup);
PG_RETURN_TEXT_P(string_to_text(buf.data));
}
/*
* pg_get_function_result
* Get a nicely-formatted version of the result type of a function.
@ -1649,7 +1680,7 @@ print_function_rettype(StringInfo buf, HeapTuple proctup)
{
/* It might be a table function; try to print the arguments */
appendStringInfoString(&rbuf, "TABLE(");
ntabargs = print_function_arguments(&rbuf, proctup, true);
ntabargs = print_function_arguments(&rbuf, proctup, true, true);
if (ntabargs > 0)
appendStringInfoString(&rbuf, ")");
else
@ -1672,10 +1703,12 @@ print_function_rettype(StringInfo buf, HeapTuple proctup)
* append the desired subset of arguments to buf. We print only TABLE
* arguments when print_table_args is true, and all the others when it's false.
* Function return value is the number of arguments printed.
* When full is false, then don't print argument names and argument defaults.
*/
static int
print_function_arguments(StringInfo buf, HeapTuple proctup,
bool print_table_args)
bool print_table_args,
bool full)
{
int numargs;
Oid *argtypes;
@ -1683,10 +1716,37 @@ print_function_arguments(StringInfo buf, HeapTuple proctup,
char *argmodes;
int argsprinted;
int i;
Datum proargdefaults;
List *argdefaults;
int nargdefaults;
bool isnull;
List *dcontext = NIL;
numargs = get_func_arg_info(proctup,
&argtypes, &argnames, &argmodes);
proargdefaults = SysCacheGetAttr(PROCOID, proctup,
Anum_pg_proc_proargdefaults, &isnull);
if (!isnull)
{
char *str;
str = TextDatumGetCString(proargdefaults);
argdefaults = (List *) stringToNode(str);
Assert(IsA(argdefaults, List));
nargdefaults = list_length(argdefaults);
/* we will need deparse context */
//dcontext = deparse_context_for("", InvalidOid);
dcontext = NULL;
pfree(str);
}
else
{
argdefaults = NIL;
nargdefaults = 0;
}
argsprinted = 0;
for (i = 0; i < numargs; i++)
{
@ -1723,9 +1783,19 @@ print_function_arguments(StringInfo buf, HeapTuple proctup,
if (argsprinted)
appendStringInfoString(buf, ", ");
appendStringInfoString(buf, modename);
if (argname && argname[0])
if (argname && argname[0] && full)
appendStringInfo(buf, "%s ", argname);
appendStringInfoString(buf, format_type_be(argtype));
/* search given default expression, expect less numargs */
if (nargdefaults > 0 && i >= (numargs - nargdefaults) && full)
{
Node *expr;
expr = (Node *) list_nth(argdefaults, i - (numargs - nargdefaults));
appendStringInfo(buf, " DEFAULT %s", deparse_expression(expr, dcontext, false, false));
}
argsprinted++;
}
@ -6002,7 +6072,7 @@ generate_function_name(Oid funcid, int nargs, Oid *argtypes,
p_result = func_get_detail(list_make1(makeString(proname)),
NIL, nargs, argtypes, false,
&p_funcid, &p_rettype,
&p_retset, &p_nvargs, &p_true_typeids);
&p_retset, &p_nvargs, &p_true_typeids, NULL);
if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE) &&
p_funcid == funcid)
nspname = NULL;

View File

@ -12,7 +12,7 @@
* by PostgreSQL
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.505 2008/11/09 21:24:32 tgl Exp $
* $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.506 2008/12/04 17:51:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -6733,13 +6733,15 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
PQExpBuffer delqry;
PQExpBuffer asPart;
PGresult *res;
char *funcsig;
char *funcsig; /* identity signature */
char *funcfullsig; /* full signature */
char *funcsig_tag;
int ntups;
char *proretset;
char *prosrc;
char *probin;
char *funcargs;
char *funciargs;
char *funcresult;
char *proallargtypes;
char *proargmodes;
@ -6782,6 +6784,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
appendPQExpBuffer(query,
"SELECT proretset, prosrc, probin, "
"pg_catalog.pg_get_function_arguments(oid) as funcargs, "
"pg_catalog.pg_get_function_identity_arguments(oid) as funciargs, "
"pg_catalog.pg_get_function_result(oid) as funcresult, "
"provolatile, proisstrict, prosecdef, "
"proconfig, procost, prorows, "
@ -6893,6 +6896,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
if (g_fout->remoteVersion >= 80400)
{
funcargs = PQgetvalue(res, 0, PQfnumber(res, "funcargs"));
funciargs = PQgetvalue(res, 0, PQfnumber(res, "funciargs"));
funcresult = PQgetvalue(res, 0, PQfnumber(res, "funcresult"));
proallargtypes = proargmodes = proargnames = NULL;
}
@ -6901,7 +6905,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
proallargtypes = PQgetvalue(res, 0, PQfnumber(res, "proallargtypes"));
proargmodes = PQgetvalue(res, 0, PQfnumber(res, "proargmodes"));
proargnames = PQgetvalue(res, 0, PQfnumber(res, "proargnames"));
funcargs = funcresult = NULL;
funcargs = funciargs = funcresult = NULL;
}
provolatile = PQgetvalue(res, 0, PQfnumber(res, "provolatile"));
proisstrict = PQgetvalue(res, 0, PQfnumber(res, "proisstrict"));
@ -7007,11 +7011,19 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
}
}
if (funcargs)
funcsig = format_function_arguments(finfo, funcargs);
/* funcargs and funciargs are supported from 8.4 */
if (funciargs)
{
funcsig = format_function_arguments(finfo, funciargs);
funcfullsig = format_function_arguments(finfo, funcargs);
}
else
{
funcsig = format_function_arguments_old(finfo, nallargs, allargtypes,
argmodes, argnames);
funcfullsig = funcsig;
}
funcsig_tag = format_function_signature(finfo, false);
/*
@ -7021,7 +7033,7 @@ dumpFunc(Archive *fout, FuncInfo *finfo)
fmtId(finfo->dobj.namespace->dobj.name),
funcsig);
appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcsig);
appendPQExpBuffer(q, "CREATE FUNCTION %s ", funcfullsig);
if (funcresult)
appendPQExpBuffer(q, "RETURNS %s", funcresult);
else

View File

@ -37,7 +37,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.510 2008/12/03 13:28:53 heikki Exp $
* $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.511 2008/12/04 17:51:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -53,6 +53,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 200812031
#define CATALOG_VERSION_NO 200812041
#endif

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.55 2008/07/16 01:30:23 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/namespace.h,v 1.56 2008/12/04 17:51:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -30,6 +30,7 @@ typedef struct _FuncCandidateList
Oid oid; /* the function or operator's OID */
int nargs; /* number of arg types returned */
int nvargs; /* number of args to become variadic array */
List *argdefaults; /* list of parameter defaults */
Oid args[1]; /* arg types --- VARIABLE LENGTH ARRAY */
} *FuncCandidateList; /* VARIABLE LENGTH STRUCT */

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.141 2008/11/09 21:24:33 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_attribute.h,v 1.142 2008/12/04 17:51:27 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -300,15 +300,17 @@ DATA(insert ( 1247 tableoid 26 0 4 -7 0 -1 -1 t p i t f f t 0));
{ 1255, {"proretset"}, 16, -1, 1, 11, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1255, {"provolatile"}, 18, -1, 1, 12, 0, -1, -1, true, 'p', 'c', true, false, false, true, 0 }, \
{ 1255, {"pronargs"}, 21, -1, 2, 13, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1255, {"prorettype"}, 26, -1, 4, 14, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1255, {"proargtypes"}, 30, -1, -1, 15, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
{ 1255, {"proallargtypes"}, 1028, -1, -1, 16, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proargmodes"}, 1002, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proargnames"}, 1009, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"prosrc"}, 25, -1, -1, 19, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"probin"}, 17, -1, -1, 20, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proconfig"}, 1009, -1, -1, 21, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proacl"}, 1034, -1, -1, 22, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
{ 1255, {"pronargdefaults"}, 21, -1, 2, 14, 0, -1, -1, true, 'p', 's', true, false, false, true, 0 }, \
{ 1255, {"prorettype"}, 26, -1, 4, 15, 0, -1, -1, true, 'p', 'i', true, false, false, true, 0 }, \
{ 1255, {"proargtypes"}, 30, -1, -1, 16, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0 }, \
{ 1255, {"proallargtypes"}, 1028, -1, -1, 17, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proargmodes"}, 1002, -1, -1, 18, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proargnames"}, 1009, -1, -1, 19, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proargdefaults"}, 25, -1, -1, 20, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"prosrc"}, 25, -1, -1, 21, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"probin"}, 17, -1, -1, 22, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proconfig"}, 1009, -1, -1, 23, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }, \
{ 1255, {"proacl"}, 1034, -1, -1, 24, 1, -1, -1, false, 'x', 'i', false, false, false, true, 0 }
DATA(insert ( 1255 proname 19 -1 NAMEDATALEN 1 0 -1 -1 f p c t f f t 0));
DATA(insert ( 1255 pronamespace 26 -1 4 2 0 -1 -1 t p i t f f t 0));
@ -323,15 +325,17 @@ DATA(insert ( 1255 proisstrict 16 -1 1 10 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1255 proretset 16 -1 1 11 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1255 provolatile 18 -1 1 12 0 -1 -1 t p c t f f t 0));
DATA(insert ( 1255 pronargs 21 -1 2 13 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1255 prorettype 26 -1 4 14 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1255 proargtypes 30 -1 -1 15 1 -1 -1 f p i t f f t 0));
DATA(insert ( 1255 proallargtypes 1028 -1 -1 16 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proargmodes 1002 -1 -1 17 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proargnames 1009 -1 -1 18 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 prosrc 25 -1 -1 19 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 probin 17 -1 -1 20 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proconfig 1009 -1 -1 21 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proacl 1034 -1 -1 22 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 pronargdefaults 21 -1 2 14 0 -1 -1 t p s t f f t 0));
DATA(insert ( 1255 prorettype 26 -1 4 15 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1255 proargtypes 30 -1 -1 16 1 -1 -1 f p i t f f t 0));
DATA(insert ( 1255 proallargtypes 1028 -1 -1 17 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proargmodes 1002 -1 -1 18 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proargnames 1009 -1 -1 19 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proargdefaults 25 -1 -1 20 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 prosrc 25 -1 -1 21 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 probin 17 -1 -1 22 0 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proconfig 1009 -1 -1 23 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 proacl 1034 -1 -1 24 1 -1 -1 f x i f f f t 0));
DATA(insert ( 1255 ctid 27 0 6 -1 0 -1 -1 f p s t f f t 0));
DATA(insert ( 1255 oid 26 0 4 -2 0 -1 -1 t p i t f f t 0));
DATA(insert ( 1255 xmin 28 0 4 -3 0 -1 -1 t p i t f f t 0));

View File

@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.108 2008/11/09 21:24:33 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_class.h,v 1.109 2008/12/04 17:51:27 petere Exp $
*
* NOTES
* the genbki.sh script reads this file and generates .bki
@ -125,7 +125,7 @@ DATA(insert OID = 1247 ( pg_type PGNSP 71 PGUID 0 1247 0 0 0 0 0 f f r 28 0 t
DESCR("");
DATA(insert OID = 1249 ( pg_attribute PGNSP 75 PGUID 0 1249 0 0 0 0 0 f f r 17 0 f f f f f 3 _null_ _null_ ));
DESCR("");
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 22 0 t f f f f 3 _null_ _null_ ));
DATA(insert OID = 1255 ( pg_proc PGNSP 81 PGUID 0 1255 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
DESCR("");
DATA(insert OID = 1259 ( pg_class PGNSP 83 PGUID 0 1259 0 0 0 0 0 f f r 24 0 t f f f f 3 _null_ _null_ ));
DESCR("");

File diff suppressed because it is too large Load Diff

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/catalog/pg_proc_fn.h,v 1.1 2008/03/27 03:57:34 tgl Exp $
* $PostgreSQL: pgsql/src/include/catalog/pg_proc_fn.h,v 1.2 2008/12/04 17:51:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -33,7 +33,8 @@ extern Oid ProcedureCreate(const char *procedureName,
Datum parameterNames,
Datum proconfig,
float4 procost,
float4 prorows);
float4 prorows,
List *parameterDefaults);
extern bool function_parse_error_transpose(const char *prosrc);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.89 2008/06/14 18:04:34 tgl Exp $
* $PostgreSQL: pgsql/src/include/commands/defrem.h,v 1.90 2008/12/04 17:51:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -45,7 +45,7 @@ extern char *ChooseRelationName(const char *name1, const char *name2,
extern Oid GetDefaultOpClass(Oid type_id, Oid am_id);
/* commands/functioncmds.c */
extern void CreateFunction(CreateFunctionStmt *stmt);
extern void CreateFunction(CreateFunctionStmt *stmt, const char *queryString);
extern void RemoveFunction(RemoveFuncStmt *stmt);
extern void RemoveFunctionById(Oid funcOid);
extern void SetFunctionReturnType(Oid funcOid, Oid newRetType);

View File

@ -13,7 +13,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.380 2008/12/04 11:42:24 heikki Exp $
* $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.381 2008/12/04 17:51:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -1686,6 +1686,7 @@ typedef struct FunctionParameter
char *name; /* parameter name, or NULL if not given */
TypeName *argType; /* TypeName for parameter type */
FunctionParameterMode mode; /* IN/OUT/INOUT */
Node *defexpr; /* Default expression, or NULL if not given */
} FunctionParameter;
typedef struct AlterFunctionStmt

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.60 2008/07/16 01:30:23 tgl Exp $
* $PostgreSQL: pgsql/src/include/parser/parse_func.h,v 1.61 2008/12/04 17:51:27 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -49,7 +49,8 @@ extern Node *ParseFuncOrColumn(ParseState *pstate,
extern FuncDetailCode func_get_detail(List *funcname, List *fargs,
int nargs, Oid *argtypes, bool expand_variadic,
Oid *funcid, Oid *rettype,
bool *retset, int *nvargs, Oid **true_typeids);
bool *retset, int *nvargs, Oid **true_typeids,
List **argdefaults);
extern int func_match_argtypes(int nargs,
Oid *input_typeids,

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.326 2008/11/03 20:17:20 adunstan Exp $
* $PostgreSQL: pgsql/src/include/utils/builtins.h,v 1.327 2008/12/04 17:51:28 petere Exp $
*
*-------------------------------------------------------------------------
*/
@ -553,6 +553,7 @@ extern Datum pg_get_userbyid(PG_FUNCTION_ARGS);
extern Datum pg_get_serial_sequence(PG_FUNCTION_ARGS);
extern Datum pg_get_functiondef(PG_FUNCTION_ARGS);
extern Datum pg_get_function_arguments(PG_FUNCTION_ARGS);
extern Datum pg_get_function_identity_arguments(PG_FUNCTION_ARGS);
extern Datum pg_get_function_result(PG_FUNCTION_ARGS);
extern char *deparse_expression(Node *expr, List *dpcontext,
bool forceprefix, bool showimplicit);

View File

@ -61,6 +61,14 @@ WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
-----+---------
(0 rows)
-- pronargdefaults should be 0 iff proargdefaults is null
SELECT p.oid, p.proname
FROM pg_proc AS p
WHERE pronargdefaults <> 0 OR proargdefaults IS NOT NULL;
oid | proname
-----+---------
(0 rows)
-- probin should be non-empty for C functions, null everywhere else
SELECT p1.oid, p1.proname
FROM pg_proc as p1

View File

@ -776,3 +776,190 @@ select pg_typeof(myleast(10, 1, 20, 33)); -- polymorphic input
integer
(1 row)
-- test functions with parameter defaults
-- test basic functionality
create function dfunc(a int = 1, int = 2) returns int as $$
select $1 + $2;
$$ language sql;
select dfunc();
dfunc
-------
3
(1 row)
select dfunc(10);
dfunc
-------
12
(1 row)
select dfunc(10, 20);
dfunc
-------
30
(1 row)
drop function dfunc(); -- fail
ERROR: function dfunc() does not exist
drop function dfunc(int); -- fail
ERROR: function dfunc(integer) does not exist
drop function dfunc(int, int); -- ok
-- fail, gap in arguments with defaults
create function dfunc(a int = 1, b int) returns int as $$
select $1 + $2;
$$ language sql;
ERROR: parameter without default value specified after parameter with default value
-- check implicit coercion
create function dfunc(a int DEFAULT 1.0, int DEFAULT '-1') returns int as $$
select $1 + $2;
$$ language sql;
select dfunc();
dfunc
-------
0
(1 row)
create function dfunc(a text DEFAULT 'Hello', b text DEFAULT 'World') returns text as $$
select $1 || ', ' || $2;
$$ language sql;
select dfunc(); -- fail; which dfunc should be called? int or text
ERROR: functions with parameter defaults dfunc(text, text) and dfunc(integer, integer) are ambiguous
select dfunc('Hi'); -- ok
dfunc
-----------
Hi, World
(1 row)
select dfunc('Hi', 'City'); -- ok
dfunc
----------
Hi, City
(1 row)
select dfunc(0); -- ok
dfunc
-------
-1
(1 row)
select dfunc(10, 20); -- ok
dfunc
-------
30
(1 row)
drop function dfunc(int, int);
drop function dfunc(text, text);
create function dfunc(int = 1, int = 2) returns int as $$
select 2;
$$ language sql;
create function dfunc(int = 1, int = 2, int = 3, int = 4) returns int as $$
select 4;
$$ language sql;
-- Now, dfunc(nargs = 2) and dfunc(nargs = 4) are ambiguous when called
-- with 0 or 1 arguments. For 2 arguments, a normall call of
-- dfunc(nargs = 2) takes place.
select dfunc(); -- fail
ERROR: functions with parameter defaults dfunc(integer, integer, integer, integer) and dfunc(integer, integer) are ambiguous
select dfunc(1); -- fail
ERROR: functions with parameter defaults dfunc(integer, integer, integer, integer) and dfunc(integer, integer) are ambiguous
select dfunc(1, 2); -- ok
dfunc
-------
2
(1 row)
select dfunc(1, 2, 3); -- ok
dfunc
-------
4
(1 row)
select dfunc(1, 2, 3, 4); -- ok
dfunc
-------
4
(1 row)
drop function dfunc(int, int);
drop function dfunc(int, int, int, int);
-- default values are not allowed for output parameters
create function dfunc(out int = 20) returns int as $$
select 1;
$$ language sql;
ERROR: only IN and INOUT parameters can have default values
-- polymorphic parameter test
create function dfunc(anyelement = 'World'::text) returns text as $$
select 'Hello, ' || $1::text;
$$ language sql;
select dfunc();
dfunc
--------------
Hello, World
(1 row)
select dfunc(0);
dfunc
----------
Hello, 0
(1 row)
select dfunc(to_date('20081215','YYYYMMDD'));
dfunc
-------------------
Hello, 12-15-2008
(1 row)
select dfunc('City'::text);
dfunc
-------------
Hello, City
(1 row)
drop function dfunc(anyelement);
-- check null values
create function dfunc(int = null, int = null, int = null) returns int[] as $$
select array[$1, $2, $3];
$$ language sql;
select dfunc(1);
dfunc
---------------
{1,NULL,NULL}
(1 row)
select dfunc(1, 2);
dfunc
------------
{1,2,NULL}
(1 row)
select dfunc(1, 2, 3);
dfunc
---------
{1,2,3}
(1 row)
drop function dfunc(int, int, int);
-- The conflict detection algorithm doesn't consider the actual parameter
-- types. It detects any possible conflict for n arguments for some
-- function. This is unwanted behavior, but solving it needs a move of
-- coercion routines.
create function dfunc(int = 1, int = 2, int = 3) returns int as $$
select 3;
$$ language sql;
create function dfunc(int = 1, int = 2) returns int as $$
select 2;
$$ language sql;
-- for n = 1 dfunc(narg=2) and dfunc(narg=3) are ambiguous
select dfunc(1); -- fail
ERROR: functions with parameter defaults dfunc(integer, integer, integer) and dfunc(integer, integer) are ambiguous
create function dfunc(text) returns text as $$
select $1;
$$ language sql;
-- Will fail, it detects ambiguity between dfunc(int, int, int) and
-- dfunc(int, int), but dfunc(text) isn't in conflict with either.
select dfunc('Hi');
ERROR: functions with parameter defaults dfunc(integer, integer, integer) and dfunc(integer, integer) are ambiguous
drop function dfunc(int, int, int);
drop function dfunc(int, int);
drop function dfunc(text);

View File

@ -62,6 +62,11 @@ SELECT p1.oid, p1.proname
FROM pg_proc as p1
WHERE prosrc IS NULL OR prosrc = '' OR prosrc = '-';
-- pronargdefaults should be 0 iff proargdefaults is null
SELECT p.oid, p.proname
FROM pg_proc AS p
WHERE pronargdefaults <> 0 OR proargdefaults IS NOT NULL;
-- probin should be non-empty for C functions, null everywhere else
SELECT p1.oid, p1.proname
FROM pg_proc as p1

View File

@ -480,3 +480,117 @@ select pg_typeof('' || ''); -- text
select pg_typeof(pg_typeof(0)); -- regtype
select pg_typeof(array[1.2,55.5]); -- numeric[]
select pg_typeof(myleast(10, 1, 20, 33)); -- polymorphic input
-- test functions with parameter defaults
-- test basic functionality
create function dfunc(a int = 1, int = 2) returns int as $$
select $1 + $2;
$$ language sql;
select dfunc();
select dfunc(10);
select dfunc(10, 20);
drop function dfunc(); -- fail
drop function dfunc(int); -- fail
drop function dfunc(int, int); -- ok
-- fail, gap in arguments with defaults
create function dfunc(a int = 1, b int) returns int as $$
select $1 + $2;
$$ language sql;
-- check implicit coercion
create function dfunc(a int DEFAULT 1.0, int DEFAULT '-1') returns int as $$
select $1 + $2;
$$ language sql;
select dfunc();
create function dfunc(a text DEFAULT 'Hello', b text DEFAULT 'World') returns text as $$
select $1 || ', ' || $2;
$$ language sql;
select dfunc(); -- fail; which dfunc should be called? int or text
select dfunc('Hi'); -- ok
select dfunc('Hi', 'City'); -- ok
select dfunc(0); -- ok
select dfunc(10, 20); -- ok
drop function dfunc(int, int);
drop function dfunc(text, text);
create function dfunc(int = 1, int = 2) returns int as $$
select 2;
$$ language sql;
create function dfunc(int = 1, int = 2, int = 3, int = 4) returns int as $$
select 4;
$$ language sql;
-- Now, dfunc(nargs = 2) and dfunc(nargs = 4) are ambiguous when called
-- with 0 or 1 arguments. For 2 arguments, a normall call of
-- dfunc(nargs = 2) takes place.
select dfunc(); -- fail
select dfunc(1); -- fail
select dfunc(1, 2); -- ok
select dfunc(1, 2, 3); -- ok
select dfunc(1, 2, 3, 4); -- ok
drop function dfunc(int, int);
drop function dfunc(int, int, int, int);
-- default values are not allowed for output parameters
create function dfunc(out int = 20) returns int as $$
select 1;
$$ language sql;
-- polymorphic parameter test
create function dfunc(anyelement = 'World'::text) returns text as $$
select 'Hello, ' || $1::text;
$$ language sql;
select dfunc();
select dfunc(0);
select dfunc(to_date('20081215','YYYYMMDD'));
select dfunc('City'::text);
drop function dfunc(anyelement);
-- check null values
create function dfunc(int = null, int = null, int = null) returns int[] as $$
select array[$1, $2, $3];
$$ language sql;
select dfunc(1);
select dfunc(1, 2);
select dfunc(1, 2, 3);
drop function dfunc(int, int, int);
-- The conflict detection algorithm doesn't consider the actual parameter
-- types. It detects any possible conflict for n arguments for some
-- function. This is unwanted behavior, but solving it needs a move of
-- coercion routines.
create function dfunc(int = 1, int = 2, int = 3) returns int as $$
select 3;
$$ language sql;
create function dfunc(int = 1, int = 2) returns int as $$
select 2;
$$ language sql;
-- for n = 1 dfunc(narg=2) and dfunc(narg=3) are ambiguous
select dfunc(1); -- fail
create function dfunc(text) returns text as $$
select $1;
$$ language sql;
-- Will fail, it detects ambiguity between dfunc(int, int, int) and
-- dfunc(int, int), but dfunc(text) isn't in conflict with either.
select dfunc('Hi');
drop function dfunc(int, int, int);
drop function dfunc(int, int);
drop function dfunc(text);