aboutsummaryrefslogtreecommitdiff
path: root/src/backend
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend')
-rw-r--r--src/backend/catalog/namespace.c87
-rw-r--r--src/backend/catalog/pg_aggregate.c7
-rw-r--r--src/backend/catalog/pg_proc.c13
-rw-r--r--src/backend/commands/functioncmds.c48
-rw-r--r--src/backend/commands/proclang.c8
-rw-r--r--src/backend/nodes/copyfuncs.c3
-rw-r--r--src/backend/nodes/equalfuncs.c3
-rw-r--r--src/backend/parser/gram.y48
-rw-r--r--src/backend/parser/parse_func.c25
-rw-r--r--src/backend/tcop/utility.c4
-rw-r--r--src/backend/utils/adt/ruleutils.c86
11 files changed, 292 insertions, 40 deletions
diff --git a/src/backend/catalog/namespace.c b/src/backend/catalog/namespace.c
index f1763e5199c..6c83755a4c7 100644
--- a/src/backend/catalog/namespace.c
+++ b/src/backend/catalog/namespace.c
@@ -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 */
}
diff --git a/src/backend/catalog/pg_aggregate.c b/src/backend/catalog/pg_aggregate.c
index fc5ed839376..7cd0d513ed0 100644
--- a/src/backend/catalog/pg_aggregate.c
+++ b/src/backend/catalog/pg_aggregate.c
@@ -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))
diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c
index e17aa43fd5c..1b414e3e5a6 100644
--- a/src/backend/catalog/pg_proc.c
+++ b/src/backend/catalog/pg_proc.c
@@ -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);
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 97cde6419d1..1509da73124 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -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);
}
diff --git a/src/backend/commands/proclang.c b/src/backend/commands/proclang.c
index 6827834f30c..2166a1de5fe 100644
--- a/src/backend/commands/proclang.c
+++ b/src/backend/commands/proclang.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $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
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 54358191f5f..6a0c3374ce8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $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;
}
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 002740f784a..ebf8cea2f0d 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -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;
}
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 703533891f3..4a8bf5fd421 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -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);
@@ -4224,6 +4225,21 @@ func_args_list:
;
/*
+ * 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
* anyway. Don't bother trying to save productions by letting arg_class
@@ -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 */
diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c
index bbbc5fe7a94..1171d367c6f 100644
--- a/src/backend/parser/parse_func.c
+++ b/src/backend/parser/parse_func.c
@@ -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),
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 6893b9ed179..f222b9cd75e 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -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 */
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c
index 7a89bcb2dc1..afa19b384e7 100644
--- a/src/backend/utils/adt/ruleutils.c
+++ b/src/backend/utils/adt/ruleutils.c
@@ -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,7 +1599,7 @@ 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);
@@ -1606,6 +1607,36 @@ pg_get_function_arguments(PG_FUNCTION_ARGS)
}
/*
+ * 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.
* This is what would appear after RETURNS in CREATE 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;