mirror of
https://github.com/postgres/postgres.git
synced 2025-08-22 21:53:06 +03:00
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.
This commit is contained in:
@@ -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;
|
||||
|
@@ -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,21 +236,29 @@ 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,
|
||||
* possibly adjusting return type or declared_arg_types (which will be
|
||||
@@ -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)
|
||||
{
|
||||
|
Reference in New Issue
Block a user