diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 48 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 25 |
2 files changed, 65 insertions, 8 deletions
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), |