diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2008-12-18 18:20:35 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2008-12-18 18:20:35 +0000 |
commit | 517ae4039ebe12806d76adfd3bc1fc6578fc8862 (patch) | |
tree | acaa1149e46258e1625e3ff316d7caebb5f72f01 /src/backend/parser | |
parent | cee63eab8dd52b5341ecde40b684d400eb09bf0b (diff) | |
download | postgresql-517ae4039ebe12806d76adfd3bc1fc6578fc8862.tar.gz postgresql-517ae4039ebe12806d76adfd3bc1fc6578fc8862.zip |
Code review for function default parameters patch. Fix numerous problems as
per recent discussions. In passing this also fixes a couple of bugs in
the previous variadic-parameters patch.
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/gram.y | 23 | ||||
-rw-r--r-- | src/backend/parser/parse_func.c | 93 |
2 files changed, 83 insertions, 33 deletions
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index e53333d30c9..337af633272 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.644 2008/12/17 09:15:02 heikki Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.645 2008/12/18 18:20:34 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -3465,7 +3465,7 @@ opt_restart_seqs: * * COMMENT ON [ [ DATABASE | DOMAIN | INDEX | SEQUENCE | TABLE | TYPE | VIEW | * CONVERSION | LANGUAGE | OPERATOR CLASS | LARGE OBJECT | - * CAST | COLUMN | SCHEMA | TABLESPACE | ROLE | + * CAST | COLUMN | SCHEMA | TABLESPACE | ROLE | * TEXT SEARCH PARSER | TEXT SEARCH DICTIONARY | * TEXT SEARCH TEMPLATE | * TEXT SEARCH CONFIGURATION ] <objname> | @@ -4230,15 +4230,15 @@ func_args_list: */ func_args_with_defaults: '(' func_args_with_defaults_list ')' { $$ = $2; } - | '(' ')' { $$ = NIL; } + | '(' ')' { $$ = 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); } + 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 @@ -4345,7 +4345,7 @@ func_type: Typename { $$ = $1; } func_arg_with_default: func_arg - { + { $$ = $1; } | func_arg DEFAULT a_expr @@ -4459,6 +4459,7 @@ table_func_column: param_name func_type n->name = $1; n->argType = $2; n->mode = FUNC_PARAM_TABLE; + n->defexpr = NULL; $$ = n; } ; @@ -5755,7 +5756,7 @@ AlterTSConfigurationStmt: n->replace = false; $$ = (Node*)n; } - | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name WITH any_name + | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING REPLACE any_name WITH any_name { AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); n->cfgname = $5; @@ -5765,7 +5766,7 @@ AlterTSConfigurationStmt: n->replace = true; $$ = (Node*)n; } - | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name WITH any_name + | ALTER TEXT_P SEARCH CONFIGURATION any_name ALTER MAPPING FOR name_list REPLACE any_name WITH any_name { AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); n->cfgname = $5; @@ -5775,7 +5776,7 @@ AlterTSConfigurationStmt: n->replace = true; $$ = (Node*)n; } - | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list + | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING FOR name_list { AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); n->cfgname = $5; @@ -5783,7 +5784,7 @@ AlterTSConfigurationStmt: n->missing_ok = false; $$ = (Node*)n; } - | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list + | ALTER TEXT_P SEARCH CONFIGURATION any_name DROP MAPPING IF_P EXISTS FOR name_list { AlterTSConfigurationStmt *n = makeNode(AlterTSConfigurationStmt); n->cfgname = $5; diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 1171d367c6f..d0b74ff5d96 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.208 2008/12/04 17:51:26 petere Exp $ + * $PostgreSQL: pgsql/src/backend/parser/parse_func.c,v 1.209 2008/12/18 18:20:34 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -71,13 +71,14 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, ListCell *nextl; Node *first_arg = NULL; int nargs; + int nargsplusdefs; Oid actual_arg_types[FUNC_MAX_ARGS]; Oid *declared_arg_types; + List *argdefaults; Node *retval; bool retset; int nvargs; FuncDetailCode fdresult; - List *argdefaults; /* * Most of the rest of the parser just assumes that functions do not have @@ -157,13 +158,13 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, * disambiguation for polymorphic functions, handles inheritance, and * returns the funcid and type and set or singleton status of the * function's return value. It also returns the true argument types to - * the function. (In the case of a variadic function call, the reported + * the function. In the case of a variadic function call, the reported * "true" types aren't really what is in pg_proc: the variadic argument is * replaced by a suitable number of copies of its element type. We'll fix - * it up below.) + * it up below. We may also have to deal with default arguments. */ fdresult = func_get_detail(funcname, fargs, nargs, actual_arg_types, - !func_variadic, + !func_variadic, true, &funcid, &rettype, &retset, &nvargs, &declared_arg_types, &argdefaults); if (fdresult == FUNCDETAIL_COERCION) @@ -235,20 +236,28 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, parser_errposition(pstate, location))); } - /* add stored expressions as called values for arguments with defaults */ - if (argdefaults) + /* + * If there are default arguments, we have to include their types in + * actual_arg_types for the purpose of checking generic type consistency. + * However, we do NOT put them into the generated parse node, because + * their actual values might change before the query gets run. The + * planner has to insert the up-to-date values at plan time. + */ + nargsplusdefs = nargs; + foreach(l, argdefaults) { - ListCell *lc; + Node *expr = (Node *) lfirst(l); - foreach(lc, argdefaults) - { - Node *expr = (Node *) lfirst(lc); - - fargs = lappend(fargs, expr); - actual_arg_types[nargs++] = exprType(expr); - } - } + /* probably shouldn't happen ... */ + if (nargsplusdefs >= FUNC_MAX_ARGS) + ereport(ERROR, + (errcode(ERRCODE_TOO_MANY_ARGUMENTS), + errmsg("cannot pass more than %d arguments to a function", + FUNC_MAX_ARGS), + parser_errposition(pstate, location))); + actual_arg_types[nargsplusdefs++] = exprType(expr); + } /* * enforce consistency with polymorphic argument and return types, @@ -257,7 +266,7 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, */ rettype = enforce_generic_type_consistency(actual_arg_types, declared_arg_types, - nargs, + nargsplusdefs, rettype, false); @@ -741,18 +750,20 @@ func_get_detail(List *funcname, int nargs, Oid *argtypes, bool expand_variadic, + bool expand_defaults, Oid *funcid, /* return value */ Oid *rettype, /* return value */ bool *retset, /* return value */ int *nvargs, /* return value */ Oid **true_typeids, /* return value */ - List **argdefaults) /* return value */ + List **argdefaults) /* optional return value */ { FuncCandidateList raw_candidates; FuncCandidateList best_candidate; /* Get list of possible candidates from namespace search */ - raw_candidates = FuncnameGetCandidates(funcname, nargs, expand_variadic); + raw_candidates = FuncnameGetCandidates(funcname, nargs, + expand_variadic, expand_defaults); /* * Quickly check if there is an exact match to the input datatypes (there @@ -884,11 +895,17 @@ func_get_detail(List *funcname, Form_pg_proc pform; FuncDetailCode result; + /* + * If expanding variadics or defaults, the "best candidate" might + * represent multiple equivalently good functions; treat this case + * as ambiguous. + */ + if (!OidIsValid(best_candidate->oid)) + return FUNCDETAIL_MULTIPLE; + *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), @@ -899,6 +916,38 @@ func_get_detail(List *funcname, pform = (Form_pg_proc) GETSTRUCT(ftup); *rettype = pform->prorettype; *retset = pform->proretset; + /* fetch default args if caller wants 'em */ + if (argdefaults) + { + if (best_candidate->ndargs > 0) + { + Datum proargdefaults; + bool isnull; + char *str; + List *defaults; + int ndelete; + + /* shouldn't happen, FuncnameGetCandidates messed up */ + if (best_candidate->ndargs > pform->pronargdefaults) + elog(ERROR, "not enough default arguments"); + + proargdefaults = SysCacheGetAttr(PROCOID, ftup, + Anum_pg_proc_proargdefaults, + &isnull); + Assert(!isnull); + str = TextDatumGetCString(proargdefaults); + defaults = (List *) stringToNode(str); + Assert(IsA(defaults, List)); + pfree(str); + /* Delete any unused defaults from the returned list */ + ndelete = list_length(defaults) - best_candidate->ndargs; + while (ndelete-- > 0) + defaults = list_delete_first(defaults); + *argdefaults = defaults; + } + else + *argdefaults = NIL; + } result = pform->proisagg ? FUNCDETAIL_AGGREGATE : FUNCDETAIL_NORMAL; ReleaseSysCache(ftup); return result; @@ -1243,7 +1292,7 @@ LookupFuncName(List *funcname, int nargs, const Oid *argtypes, bool noError) { FuncCandidateList clist; - clist = FuncnameGetCandidates(funcname, nargs, false); + clist = FuncnameGetCandidates(funcname, nargs, false, false); while (clist) { |