diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 3da79cc4957cdaafdf05ec361183dc57dc58422e..4ed18ee5cd0e6822ad57477e7d4190537c529f7f 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.143 2003/07/01 00:04:37 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.144 2003/07/01 19:07:02 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -30,6 +30,7 @@ #include "optimizer/var.h" #include "parser/analyze.h" #include "parser/parse_clause.h" +#include "parser/parse_expr.h" #include "tcop/tcopprot.h" #include "utils/acl.h" #include "utils/builtins.h" @@ -1719,6 +1720,8 @@ inline_function(Oid funcid, Oid result_type, List *args, { Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); char result_typtype; + bool polymorphic = false; + Oid argtypes[FUNC_MAX_ARGS]; char *src; Datum tmp; bool isNull; @@ -1731,7 +1734,6 @@ inline_function(Oid funcid, Oid result_type, List *args, int *usecounts; List *arg; int i; - int j; /* * Forget it if the function is not SQL-language or has other @@ -1743,17 +1745,15 @@ inline_function(Oid funcid, Oid result_type, List *args, funcform->pronargs != length(args)) return NULL; - /* Forget it if declared return type is not base or domain */ + /* Forget it if declared return type is not base, domain, or polymorphic */ result_typtype = get_typtype(funcform->prorettype); if (result_typtype != 'b' && result_typtype != 'd') - return NULL; - - /* Forget it if any declared argument type is polymorphic */ - for (j = 0; j < funcform->pronargs; j++) { - if (funcform->proargtypes[j] == ANYARRAYOID || - funcform->proargtypes[j] == ANYELEMENTOID) + if (funcform->prorettype == ANYARRAYOID || + funcform->prorettype == ANYELEMENTOID) + polymorphic = true; + else return NULL; } @@ -1765,6 +1765,18 @@ inline_function(Oid funcid, Oid result_type, List *args, if (pg_proc_aclcheck(funcid, GetUserId(), ACL_EXECUTE) != ACLCHECK_OK) return NULL; + /* Check for polymorphic arguments, and substitute actual arg types */ + memcpy(argtypes, funcform->proargtypes, FUNC_MAX_ARGS * sizeof(Oid)); + for (i = 0; i < funcform->pronargs; i++) + { + if (argtypes[i] == ANYARRAYOID || + argtypes[i] == ANYELEMENTOID) + { + polymorphic = true; + argtypes[i] = exprType((Node *) nth(i, args)); + } + } + /* * Make a temporary memory context, so that we don't leak all the * stuff that parsing might create. @@ -1797,8 +1809,7 @@ inline_function(Oid funcid, Oid result_type, List *args, goto fail; querytree_list = parse_analyze(lfirst(raw_parsetree_list), - funcform->proargtypes, - funcform->pronargs); + argtypes, funcform->pronargs); if (length(querytree_list) != 1) goto fail; @@ -1829,6 +1840,18 @@ inline_function(Oid funcid, Oid result_type, List *args, newexpr = (Node *) ((TargetEntry *) lfirst(querytree->targetList))->expr; + /* + * If the function has any arguments declared as polymorphic types, + * then it wasn't type-checked at definition time; must do so now. + * (This will raise an error if wrong, but that's okay since the + * function would fail at runtime anyway. Note we do not try this + * until we have verified that no rewriting was needed; that's probably + * not important, but let's be careful.) + */ + if (polymorphic) + check_sql_fn_retval(result_type, get_typtype(result_type), + querytree_list); + /* * Additional validity checks on the expression. It mustn't return a * set, and it mustn't be more volatile than the surrounding function