diff options
Diffstat (limited to 'src/backend')
-rw-r--r-- | src/backend/catalog/namespace.c | 87 | ||||
-rw-r--r-- | src/backend/catalog/pg_aggregate.c | 7 | ||||
-rw-r--r-- | src/backend/catalog/pg_proc.c | 13 | ||||
-rw-r--r-- | src/backend/commands/functioncmds.c | 48 | ||||
-rw-r--r-- | src/backend/commands/proclang.c | 8 | ||||
-rw-r--r-- | src/backend/nodes/copyfuncs.c | 3 | ||||
-rw-r--r-- | src/backend/nodes/equalfuncs.c | 3 | ||||
-rw-r--r-- | src/backend/parser/gram.y | 48 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 25 | ||||
-rw-r--r-- | src/backend/tcop/utility.c | 4 | ||||
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 86 |
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, ¶meterModes, ¶meterNames, - &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; |