Index: src/pl/plpgsql/src/pl_comp.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_comp.c,v retrieving revision 1.58 diff -c -r1.58 pl_comp.c *** src/pl/plpgsql/src/pl_comp.c 5 May 2003 16:46:27 -0000 1.58 --- src/pl/plpgsql/src/pl_comp.c 30 Jun 2003 05:36:10 -0000 *************** *** 108,114 **** * ---------- */ PLpgSQL_function * ! plpgsql_compile(Oid fn_oid, int functype) { int parse_rc; HeapTuple procTup; --- 108,116 ---- * ---------- */ PLpgSQL_function * ! plpgsql_compile(Oid fn_oid, ! int functype, ! FunctionCallInfo fcinfo) { int parse_rc; HeapTuple procTup; *************** *** 123,128 **** --- 125,131 ---- int i; int arg_varnos[FUNC_MAX_ARGS]; ErrorContextCallback plerrcontext; + Oid rettypeid; /* * Lookup the pg_proc tuple by Oid *************** *** 185,223 **** case T_FUNCTION: /* * Normal function has a defined returntype */ ! function->fn_rettype = procStruct->prorettype; function->fn_retset = procStruct->proretset; /* * Lookup the functions return type */ typeTup = SearchSysCache(TYPEOID, ! ObjectIdGetDatum(procStruct->prorettype), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup for return type %u failed", ! procStruct->prorettype); typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype result, except VOID or RECORD */ if (typeStruct->typtype == 'p') { ! if (procStruct->prorettype == VOIDOID || ! procStruct->prorettype == RECORDOID) /* okay */ ; ! else if (procStruct->prorettype == TRIGGEROID) elog(ERROR, "plpgsql functions cannot return type %s" "\n\texcept when used as triggers", ! format_type_be(procStruct->prorettype)); else elog(ERROR, "plpgsql functions cannot return type %s", ! format_type_be(procStruct->prorettype)); } if (typeStruct->typrelid != InvalidOid || ! procStruct->prorettype == RECORDOID) function->fn_retistuple = true; else { --- 188,241 ---- case T_FUNCTION: /* + * Check for a polymorphic returntype. If found, use the actual + * returntype from the caller's FuncExpr node, if we + * have one. + */ + if (procStruct->prorettype == ANYARRAYOID || + procStruct->prorettype == ANYELEMENTOID) + { + rettypeid = get_fn_expr_rettype(fcinfo); + if (!OidIsValid(rettypeid)) + rettypeid = procStruct->prorettype; + } + else + rettypeid = procStruct->prorettype; + + /* * Normal function has a defined returntype */ ! function->fn_rettype = rettypeid; function->fn_retset = procStruct->proretset; /* * Lookup the functions return type */ typeTup = SearchSysCache(TYPEOID, ! ObjectIdGetDatum(rettypeid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup for return type %u failed", ! rettypeid); typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype result, except VOID or RECORD */ if (typeStruct->typtype == 'p') { ! if (rettypeid == VOIDOID || ! rettypeid == RECORDOID) /* okay */ ; ! else if (rettypeid == TRIGGEROID) elog(ERROR, "plpgsql functions cannot return type %s" "\n\texcept when used as triggers", ! format_type_be(rettypeid)); else elog(ERROR, "plpgsql functions cannot return type %s", ! format_type_be(rettypeid)); } if (typeStruct->typrelid != InvalidOid || ! rettypeid == RECORDOID) function->fn_retistuple = true; else { *************** *** 234,257 **** for (i = 0; i < procStruct->pronargs; i++) { char buf[32]; snprintf(buf, sizeof(buf), "$%d", i + 1); /* name for variable */ /* * Get the parameters type */ typeTup = SearchSysCache(TYPEOID, ! ObjectIdGetDatum(procStruct->proargtypes[i]), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup for argument type %u failed", ! procStruct->proargtypes[i]); typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype argument */ if (typeStruct->typtype == 'p') elog(ERROR, "plpgsql functions cannot take type %s", ! format_type_be(procStruct->proargtypes[i])); if (typeStruct->typrelid != InvalidOid) { --- 252,291 ---- for (i = 0; i < procStruct->pronargs; i++) { char buf[32]; + Oid argtypeid = InvalidOid; snprintf(buf, sizeof(buf), "$%d", i + 1); /* name for variable */ /* + * Check for polymorphic arguments. If found, use the actual + * parameter type from the caller's FuncExpr node, if we + * have one. + */ + if (procStruct->proargtypes[i] == ANYARRAYOID || + procStruct->proargtypes[i] == ANYELEMENTOID) + { + argtypeid = get_fn_expr_argtype(fcinfo, i); + if (!OidIsValid(argtypeid)) + argtypeid = procStruct->proargtypes[i]; + } + else + argtypeid = procStruct->proargtypes[i]; + + /* * Get the parameters type */ typeTup = SearchSysCache(TYPEOID, ! ObjectIdGetDatum(argtypeid), 0, 0, 0); if (!HeapTupleIsValid(typeTup)) elog(ERROR, "cache lookup for argument type %u failed", ! argtypeid); typeStruct = (Form_pg_type) GETSTRUCT(typeTup); /* Disallow pseudotype argument */ if (typeStruct->typtype == 'p') elog(ERROR, "plpgsql functions cannot take type %s", ! format_type_be(argtypeid)); if (typeStruct->typrelid != InvalidOid) { Index: src/pl/plpgsql/src/pl_handler.c =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/pl_handler.c,v retrieving revision 1.12 diff -c -r1.12 pl_handler.c *** src/pl/plpgsql/src/pl_handler.c 30 Aug 2002 00:28:41 -0000 1.12 --- src/pl/plpgsql/src/pl_handler.c 30 Jun 2003 05:17:03 -0000 *************** *** 51,57 **** static PLpgSQL_function *compiled_functions = NULL; ! static bool func_up_to_date(PLpgSQL_function * func); /* ---------- --- 51,57 ---- static PLpgSQL_function *compiled_functions = NULL; ! static bool func_up_to_date(PLpgSQL_function * func, FunctionCallInfo fcinfo); /* ---------- *************** *** 90,96 **** /* * But is the function still up to date? */ ! if (!func_up_to_date(func)) func = NULL; } --- 90,96 ---- /* * But is the function still up to date? */ ! if (!func_up_to_date(func, fcinfo)) func = NULL; } *************** *** 101,107 **** */ for (func = compiled_functions; func != NULL; func = func->next) { ! if (funcOid == func->fn_oid && func_up_to_date(func)) break; } --- 101,107 ---- */ for (func = compiled_functions; func != NULL; func = func->next) { ! if (funcOid == func->fn_oid && func_up_to_date(func, fcinfo)) break; } *************** *** 111,117 **** if (func == NULL) { func = plpgsql_compile(funcOid, ! isTrigger ? T_TRIGGER : T_FUNCTION); func->next = compiled_functions; compiled_functions = func; } --- 111,118 ---- if (func == NULL) { func = plpgsql_compile(funcOid, ! isTrigger ? T_TRIGGER : T_FUNCTION, ! fcinfo); func->next = compiled_functions; compiled_functions = func; } *************** *** 146,154 **** * Check to see if a compiled function is still up-to-date. This * is needed because CREATE OR REPLACE FUNCTION can modify the * function's pg_proc entry without changing its OID. */ static bool ! func_up_to_date(PLpgSQL_function * func) { HeapTuple procTup; bool result; --- 147,158 ---- * Check to see if a compiled function is still up-to-date. This * is needed because CREATE OR REPLACE FUNCTION can modify the * function's pg_proc entry without changing its OID. + * A compiled function can also be out-of-date if it accepts or + * returns polymorphic types, because these may change beneath + * us. */ static bool ! func_up_to_date(PLpgSQL_function * func, FunctionCallInfo fcinfo) { HeapTuple procTup; bool result; *************** *** 162,167 **** --- 166,203 ---- result = (func->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) && func->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data)); + + /* no sense in checking if result is already false */ + if (result) + { + Form_pg_proc procStruct = (Form_pg_proc) GETSTRUCT(procTup); + + /* check for change in return type if applicable */ + if (procStruct->prorettype == ANYARRAYOID || + procStruct->prorettype == ANYELEMENTOID) + result = (func->fn_rettype == get_fn_expr_rettype(fcinfo)); + + /* check for change in any arguments' type */ + if (result) + { + int i; + + for (i = 0; i < procStruct->pronargs; i++) + { + if (procStruct->proargtypes[i] == ANYARRAYOID || + procStruct->proargtypes[i] == ANYELEMENTOID) + { + int j = func->fn_argvarnos[i]; + PLpgSQL_var *var = (PLpgSQL_var *) func->datums[j]; + Oid vartypeid = var->datatype->typoid; + + result = (vartypeid == get_fn_expr_argtype(fcinfo, i)); + if (!result) + break; + } + } + } + } ReleaseSysCache(procTup); Index: src/pl/plpgsql/src/plpgsql.h =================================================================== RCS file: /opt/src/cvs/pgsql-server/src/pl/plpgsql/src/plpgsql.h,v retrieving revision 1.36 diff -c -r1.36 plpgsql.h *** src/pl/plpgsql/src/plpgsql.h 5 May 2003 16:46:28 -0000 1.36 --- src/pl/plpgsql/src/plpgsql.h 30 Jun 2003 04:10:57 -0000 *************** *** 588,594 **** * Functions in pl_comp.c * ---------- */ ! extern PLpgSQL_function *plpgsql_compile(Oid fn_oid, int functype); extern int plpgsql_parse_word(char *word); extern int plpgsql_parse_dblword(char *word); extern int plpgsql_parse_tripword(char *word); --- 588,596 ---- * Functions in pl_comp.c * ---------- */ ! extern PLpgSQL_function *plpgsql_compile(Oid fn_oid, ! int functype, ! FunctionCallInfo fcinfo); extern int plpgsql_parse_word(char *word); extern int plpgsql_parse_dblword(char *word); extern int plpgsql_parse_tripword(char *word);