diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index e0d52d4d9b8f74fa18055eb8551b89510c5a545e..78044b2d614139f2e655dbbe35a943f53c9f9449 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.109 2007/01/05 22:19:27 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.110 2007/02/02 00:02:55 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -61,7 +61,7 @@ typedef struct { Oid *argtypes; /* resolved types of arguments */ Oid rettype; /* actual return type */ - 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 returning whole tuple result */ bool shutdown_reg; /* true if registered shutdown callback */ @@ -151,12 +151,9 @@ init_sql_fcache(FmgrInfo *finfo) Oid foid = finfo->fn_oid; Oid rettype; HeapTuple procedureTuple; - HeapTuple typeTuple; Form_pg_proc procedureStruct; - Form_pg_type typeStruct; SQLFunctionCachePtr fcache; Oid *argOidVect; - bool haspolyarg; char *src; int nargs; List *queryTree_list; @@ -193,35 +190,17 @@ init_sql_fcache(FmgrInfo *finfo) fcache->rettype = rettype; + /* Fetch the typlen and byval info for the result type */ + get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval); + /* Remember if function is STABLE/IMMUTABLE */ fcache->readonly_func = (procedureStruct->provolatile != PROVOLATILE_VOLATILE); - /* Now look up the actual result type */ - typeTuple = SearchSysCache(TYPEOID, - ObjectIdGetDatum(rettype), - 0, 0, 0); - if (!HeapTupleIsValid(typeTuple)) - elog(ERROR, "cache lookup failed for type %u", rettype); - typeStruct = (Form_pg_type) GETSTRUCT(typeTuple); - - /* - * get the type length and by-value flag from the type tuple; also do a - * preliminary check for returnsTuple (this may prove inaccurate, see - * below). - */ - fcache->typlen = typeStruct->typlen; - fcache->typbyval = typeStruct->typbyval; - fcache->returnsTuple = (typeStruct->typtype == 'c' || - rettype == RECORDOID); - /* - * Parse and rewrite the queries. We need the argument type info to pass - * to the parser. + * We need the actual argument types to pass to the parser. */ nargs = procedureStruct->pronargs; - haspolyarg = false; - if (nargs > 0) { int argnum; @@ -244,7 +223,6 @@ 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; } } } @@ -252,6 +230,9 @@ init_sql_fcache(FmgrInfo *finfo) argOidVect = NULL; fcache->argtypes = argOidVect; + /* + * Parse and rewrite the queries in the function text. + */ tmp = SysCacheGetAttr(PROCOID, procedureTuple, Anum_pg_proc_prosrc, @@ -263,24 +244,25 @@ init_sql_fcache(FmgrInfo *finfo) 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. * - * Also, force a type-check if the declared return type is a rowtype; we - * need to find out whether we are actually returning the whole tuple - * result, or just regurgitating a rowtype expression result. In the + * Note: we set fcache->returnsTuple according to whether we are + * returning the whole tuple result or just a single column. In the * latter case we clear returnsTuple because we need not act different - * from the scalar result case. + * from the scalar result case, even if it's a rowtype column. * * In the returnsTuple case, check_sql_fn_retval will also construct a * JunkFilter we can use to coerce the returned rowtype to the desired * form. */ - if (haspolyarg || fcache->returnsTuple) - fcache->returnsTuple = check_sql_fn_retval(foid, - rettype, - queryTree_list, - &fcache->junkFilter); + fcache->returnsTuple = check_sql_fn_retval(foid, + rettype, + queryTree_list, + &fcache->junkFilter); /* Finally, plan the queries */ fcache->func_state = init_execution_state(queryTree_list, @@ -288,7 +270,6 @@ init_sql_fcache(FmgrInfo *finfo) pfree(src); - ReleaseSysCache(typeTuple); ReleaseSysCache(procedureTuple); finfo->fn_extra = (void *) fcache; @@ -858,11 +839,10 @@ ShutdownSQLFunction(Datum arg) * 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.) * * The return value is true if the function returns the entire tuple result * of its final SELECT, and false otherwise. Note that because we allow diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index aac66abfba52c4583539a6fa8ad99694c3043768..10a8e80140bdf9d544c1fd71771f450360f3e68a 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.232 2007/02/01 19:10:26 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.233 2007/02/02 00:02:55 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -2751,7 +2751,6 @@ inline_function(Oid funcid, Oid result_type, List *args, eval_const_expressions_context *context) { Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); - bool polymorphic = false; Oid *argtypes; char *src; Datum tmp; @@ -2814,15 +2813,10 @@ inline_function(Oid funcid, Oid result_type, List *args, if (argtypes[i] == ANYARRAYOID || argtypes[i] == ANYELEMENTOID) { - polymorphic = true; argtypes[i] = exprType((Node *) list_nth(args, i)); } } - if (funcform->prorettype == ANYARRAYOID || - funcform->prorettype == ANYELEMENTOID) - polymorphic = true; - /* Fetch and parse the function body */ tmp = SysCacheGetAttr(PROCOID, func_tuple, @@ -2874,15 +2868,13 @@ inline_function(Oid funcid, Oid result_type, List *args, newexpr = (Node *) ((TargetEntry *) linitial(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 + * 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.) + * careful. */ - if (polymorphic) - (void) check_sql_fn_retval(funcid, result_type, querytree_list, NULL); + (void) check_sql_fn_retval(funcid, result_type, querytree_list, NULL); /* * Additional validity checks on the expression. It mustn't return a set,