diff --git a/src/backend/catalog/pg_proc.c b/src/backend/catalog/pg_proc.c index 7e797fbd4b0..8dde0578cb7 100644 --- a/src/backend/catalog/pg_proc.c +++ b/src/backend/catalog/pg_proc.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.109.2.1 2005/05/03 16:51:45 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/catalog/pg_proc.c,v 1.109.2.2 2007/02/02 00:04:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -350,11 +350,10 @@ ProcedureCreate(const char *procedureName, * the final query in the function. We do some ad-hoc type checking here * to be sure that the user is returning the type he claims. * - * This is normally applied during function definition, but in the case - * of a function with polymorphic arguments, we instead apply it during - * function execution startup. The rettype is then the actual resolved - * output type of the function, rather than the declared type. (Therefore, - * we should never see ANYARRAY or ANYELEMENT as rettype.) + * For a polymorphic function the passed rettype must be the actual resolved + * output type of the function; we should never see ANYARRAY or ANYELEMENT + * as rettype. (This means we can't check the type during function definition + * of a polymorphic function.) */ void check_sql_fn_retval(Oid rettype, char fn_typtype, List *queryTreeList) diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 6346d1abc76..b23607fb0fc 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.75.2.1 2004/09/06 18:23:09 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.75.2.2 2007/02/02 00:04:02 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -56,7 +56,7 @@ typedef struct local_es */ typedef struct { - int typlen; /* length of the return type */ + int16 typlen; /* length of the return type */ bool typbyval; /* true if return type is pass by value */ bool returnsTuple; /* true if return type is a tuple */ bool shutdown_reg; /* true if registered shutdown callback */ @@ -77,7 +77,7 @@ typedef SQLFunctionCache *SQLFunctionCachePtr; /* non-export function prototypes */ static execution_state *init_execution_state(char *src, Oid *argOidVect, int nargs, - Oid rettype, bool haspolyarg); + Oid rettype); static void init_sql_fcache(FmgrInfo *finfo); static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache); static TupleTableSlot *postquel_getnext(execution_state *es); @@ -93,7 +93,7 @@ static void ShutdownSQLFunction(Datum arg); static execution_state * init_execution_state(char *src, Oid *argOidVect, int nargs, - Oid rettype, bool haspolyarg) + Oid rettype) { execution_state *firstes; execution_state *preves; @@ -103,11 +103,13 @@ init_execution_state(char *src, Oid *argOidVect, int nargs, queryTree_list = pg_parse_and_rewrite(src, argOidVect, nargs); /* - * If the function has any arguments declared as polymorphic types, - * then it wasn't type-checked at definition time; must do so now. + * Check that the function returns the type it claims to. Although + * in simple cases this was already done when the function was defined, + * we have to recheck because database objects used in the function's + * queries might have changed type. We'd have to do it anyway if the + * function had any polymorphic arguments. */ - if (haspolyarg) - check_sql_fn_retval(rettype, get_typtype(rettype), queryTree_list); + check_sql_fn_retval(rettype, get_typtype(rettype), queryTree_list); firstes = NULL; preves = NULL; @@ -150,7 +152,6 @@ init_sql_fcache(FmgrInfo *finfo) Form_pg_type typeStruct; SQLFunctionCachePtr fcache; Oid *argOidVect; - bool haspolyarg; char *src; int nargs; Datum tmp; @@ -226,12 +227,9 @@ init_sql_fcache(FmgrInfo *finfo) fcache->funcSlot = NULL; /* - * Parse and plan the queries. We need the argument type info to pass - * to the parser. + * We need the argument type info to pass to the parser. */ nargs = procedureStruct->pronargs; - haspolyarg = false; - if (nargs > 0) { int argnum; @@ -254,13 +252,15 @@ init_sql_fcache(FmgrInfo *finfo) errmsg("could not determine actual type of argument declared %s", format_type_be(argOidVect[argnum])))); argOidVect[argnum] = argtype; - haspolyarg = true; } } } else argOidVect = (Oid *) NULL; + /* + * Parse and rewrite the queries in the function text. + */ tmp = SysCacheGetAttr(PROCOID, procedureTuple, Anum_pg_proc_prosrc, @@ -269,8 +269,7 @@ init_sql_fcache(FmgrInfo *finfo) elog(ERROR, "null prosrc for function %u", foid); src = DatumGetCString(DirectFunctionCall1(textout, tmp)); - fcache->func_state = init_execution_state(src, argOidVect, nargs, - rettype, haspolyarg); + fcache->func_state = init_execution_state(src, argOidVect, nargs, rettype); pfree(src); diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 75c1e947792..ca1f1623bd0 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.154.2.4 2005/04/14 21:44:35 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.154.2.5 2007/02/02 00:04:02 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -1758,7 +1758,6 @@ 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; @@ -1792,10 +1791,8 @@ inline_function(Oid funcid, Oid result_type, List *args, if (result_typtype != 'b' && result_typtype != 'd') { - if (funcform->prorettype == ANYARRAYOID || - funcform->prorettype == ANYELEMENTOID) - polymorphic = true; - else + if (funcform->prorettype != ANYARRAYOID && + funcform->prorettype != ANYELEMENTOID) return NULL; } @@ -1814,7 +1811,6 @@ inline_function(Oid funcid, Oid result_type, List *args, if (argtypes[i] == ANYARRAYOID || argtypes[i] == ANYELEMENTOID) { - polymorphic = true; argtypes[i] = exprType((Node *) nth(i, args)); } } @@ -1891,16 +1887,14 @@ 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.) + * Make sure the function (still) returns what it's declared to. 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); + check_sql_fn_retval(result_type, get_typtype(result_type), + querytree_list); /* * Additional validity checks on the expression. It mustn't return a