Default values for function arguments
Pavel Stehule, with some tweaks by Peter Eisentraut
This commit is contained in:
parent
7b640b0345
commit
455dffbb73
doc/src/sgml
src
backend
catalog
commands
nodes
parser
tcop
utils/adt
bin/pg_dump
include
catalog
commands
nodes
parser
utils
test/regress
@ -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>
|
||||
|
@ -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>
|
||||
|
||||
|
||||
|
@ -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>
|
||||
|
||||
|
@ -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 */
|
||||
}
|
||||
|
@ -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))
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
¶meterModes,
|
||||
¶meterNames,
|
||||
&requiredResultType);
|
||||
&defaults,
|
||||
&requiredResultType,
|
||||
queryString);
|
||||
|
||||
if (stmt->returnType)
|
||||
{
|
||||
@ -836,7 +873,8 @@ CreateFunction(CreateFunctionStmt *stmt)
|
||||
PointerGetDatum(parameterNames),
|
||||
PointerGetDatum(proconfig),
|
||||
procost,
|
||||
prorows);
|
||||
prorows,
|
||||
defaults);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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 */
|
||||
|
@ -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),
|
||||
|
@ -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 */
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 */
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user