Tom Lane wrote:
> Joe Conway wrote:
2) create hash key using a new structure that includes function oid, return type, and argument types, and use that for direct lookup.

The latter. By the time you pay the price of a hash lookup, a slightly longer key is nearly free. (Maybe entirely free, since it might produce better-distributed hash values.)

dynahash only supports fixed-length keys, so don't forget to zero out
unused positions in the argument type vector.

BTW, I can't see any need to include the return type in the hash key ---
wouldn't it be predetermined given the argument types?


The attached implements a compiled function hash in addition to the earlier changes to support PL/pgSQL polymorphism. It also includes the ealier requested change wrt generating an ERROR when faced with polymorphic arguments or return type and no FuncExpr node available.


The compiled function hash uses the following key:
typedef struct PLpgSQL_func_key
{
  Oid  funcOid;
  Oid  argtypes[FUNC_MAX_ARGS];
} PLpgSQL_func_key;

I did a simple test to check performance impact using the ealier sample function and table:

CREATE OR REPLACE FUNCTION tst(anyelement) returns anyarray as '
begin
 if $1 is of (int2, int4, int8, float4, float8, numeric) then
   return array[$1 * 2];
 elsif $1 is of (text) then
   return array[$1 || $1];
 else
   return array[$1];
 end if;
end;
' language 'plpgsql';

create table plpgsql(f1 int, f2 float8, f3 text, f4 oid);
insert into plpgsql values(1, 1.1, 'a', 1);
insert into plpgsql values(2, 2.2, 'b', 2);

---------------------------------------------------------
with original patch (linked list compiled function cache)
---------------------------------------------------------
psql regression
explain analyze SELECT tst(f1) from plpgsql; Total runtime: 3.73 msec
explain analyze SELECT tst(f1) from plpgsql; Total runtime: 0.19 msec
explain analyze SELECT tst(f2) from plpgsql; Total runtime: 1.89 msec
explain analyze SELECT tst(f2) from plpgsql; Total runtime: 0.19 msec
explain analyze SELECT tst(f3) from plpgsql; Total runtime: 1.36 msec
explain analyze SELECT tst(f3) from plpgsql; Total runtime: 0.19 msec
explain analyze SELECT tst(f4) from plpgsql; Total runtime: 0.70 msec
explain analyze SELECT tst(f4) from plpgsql; Total runtime: 0.21 msec
explain analyze SELECT tst(f1) from plpgsql; Total runtime: 0.18 msec
explain analyze SELECT tst(f2) from plpgsql; Total runtime: 0.19 msec
explain analyze SELECT tst(f3) from plpgsql; Total runtime: 0.18 msec
explain analyze SELECT tst(f4) from plpgsql; Total runtime: 0.18 msec
\q

----------------------------------------------------
with this patch (hash table compiled function cache)
----------------------------------------------------
psql regression
explain analyze SELECT tst(f1) from plpgsql; Total runtime: 2.93 msec
explain analyze SELECT tst(f1) from plpgsql; Total runtime: 0.19 msec
explain analyze SELECT tst(f2) from plpgsql; Total runtime: 1.64 msec
explain analyze SELECT tst(f2) from plpgsql; Total runtime: 0.18 msec
explain analyze SELECT tst(f3) from plpgsql; Total runtime: 1.05 msec
explain analyze SELECT tst(f3) from plpgsql; Total runtime: 0.19 msec
explain analyze SELECT tst(f4) from plpgsql; Total runtime: 0.69 msec
explain analyze SELECT tst(f4) from plpgsql; Total runtime: 0.19 msec
explain analyze SELECT tst(f1) from plpgsql; Total runtime: 0.19 msec
explain analyze SELECT tst(f2) from plpgsql; Total runtime: 0.18 msec
explain analyze SELECT tst(f3) from plpgsql; Total runtime: 0.21 msec
explain analyze SELECT tst(f4) from plpgsql; Total runtime: 0.22 msec
\q

No difference worth caring about. In more complex scenarios, the hash table cache should win hands down, I'd think.

Compiles clean, and passes all regression tests. I'll look to update the docs and regression tests as part of my post freeze array/polymorphic function cleanup.

If there are no objections, please apply.

Thanks,

Joe
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 22:20:15 -0000
***************
*** 79,88 ****
  
  PLpgSQL_function *plpgsql_curr_compile;
  
  
  static void plpgsql_compile_error_callback(void *arg);
  static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
! 
  
  /*
   * This routine is a crock, and so is everyplace that calls it.  The problem
--- 79,118 ----
  
  PLpgSQL_function *plpgsql_curr_compile;
  
+ /* ----------
+  * compiled function hash table related
+  * ----------
+  */
+ static HTAB *plpgsql_HashTable = (HTAB *) NULL;
+ 
+ typedef struct PLpgSQL_func_key
+ {
+       Oid             funcOid;
+       Oid             argtypes[FUNC_MAX_ARGS];
+ } PLpgSQL_func_key;
+ 
+ typedef struct plpgsql_hashent
+ {
+       PLpgSQL_func_key        func_key;
+       PLpgSQL_function   *function;
+ } plpgsql_HashEnt;
  
+ #define FUNCS_PER_USER                128
+ 
+ 
+ /* ----------
+  * static prototypes
+  * ----------
+  */
  static void plpgsql_compile_error_callback(void *arg);
  static PLpgSQL_type *build_datatype(HeapTuple typeTup, int32 typmod);
! static PLpgSQL_function *get_function_by_signature(FunctionCallInfo fcinfo,
!                                                                                      
            HeapTuple procTup);
! static void plpgsql_HashTableInit(void);
! static PLpgSQL_function *plpgsql_HashTableLookup(PLpgSQL_func_key *func_key);
! static void plpgsql_HashTableInsert(PLpgSQL_function *function);
! static void plpgsql_HashTableDelete(PLpgSQL_function *function);
! static PLpgSQL_func_key *function_get_func_key(PLpgSQL_function *function);
  
  /*
   * This routine is a crock, and so is everyplace that calls it.  The problem
***************
*** 108,114 ****
   * ----------
   */
  PLpgSQL_function *
! plpgsql_compile(Oid fn_oid, int functype)
  {
        int                     parse_rc;
        HeapTuple       procTup;
--- 138,144 ----
   * ----------
   */
  PLpgSQL_function *
! plpgsql_compile(FunctionCallInfo fcinfo)
  {
        int                     parse_rc;
        HeapTuple       procTup;
***************
*** 123,530 ****
        int                     i;
        int                     arg_varnos[FUNC_MAX_ARGS];
        ErrorContextCallback plerrcontext;
  
        /*
!        * Lookup the pg_proc tuple by Oid
         */
        procTup = SearchSysCache(PROCOID,
!                                                        ObjectIdGetDatum(fn_oid),
                                                         0, 0, 0);
        if (!HeapTupleIsValid(procTup))
!               elog(ERROR, "plpgsql: cache lookup for proc %u failed", fn_oid);
! 
!       /*
!        * Setup the scanner input and error info.  We assume that this function
!        * cannot be invoked recursively, so there's no need to save and restore
!        * the static variables used here.
!        */
!       procStruct = (Form_pg_proc) GETSTRUCT(procTup);
!       proc_source = DatumGetCString(DirectFunctionCall1(textout,
!                                                                 
PointerGetDatum(&procStruct->prosrc)));
!       plpgsql_scanner_init(proc_source, functype);
!       pfree(proc_source);
! 
!       plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
!       plpgsql_error_lineno = 0;
  
        /*
!        * Setup error traceback support for ereport()
         */
!       plerrcontext.callback = plpgsql_compile_error_callback;
!       plerrcontext.arg = NULL;
!       plerrcontext.previous = error_context_stack;
!       error_context_stack = &plerrcontext;
  
        /*
!        * Initialize the compiler
         */
!       plpgsql_ns_init();
!       plpgsql_ns_push(NULL);
!       plpgsql_DumpExecTree = 0;
! 
!       datums_alloc = 128;
!       plpgsql_nDatums = 0;
!       plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
!       datums_last = 0;
  
!       /*
!        * Create the new function node
!        */
!       function = malloc(sizeof(PLpgSQL_function));
!       memset(function, 0, sizeof(PLpgSQL_function));
!       plpgsql_curr_compile = function;
  
!       function->fn_name = strdup(NameStr(procStruct->proname));
!       function->fn_oid = fn_oid;
!       function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
!       function->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
!       function->fn_functype = functype;
  
!       switch (functype)
!       {
!               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
!                       {
!                               function->fn_retbyval = typeStruct->typbyval;
!                               function->fn_rettyplen = typeStruct->typlen;
!                               function->fn_rettypelem = typeStruct->typelem;
!                               perm_fmgr_info(typeStruct->typinput, 
&(function->fn_retinput));
!                       }
!                       ReleaseSysCache(typeTup);
! 
!                       /*
!                        * Create the variables for the procedures parameters
!                        */
!                       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)
                                {
                                        /*
!                                        * For tuple type parameters, we set up a 
record of
!                                        * that type
                                         */
!                                       row = 
plpgsql_build_rowtype(typeStruct->typrelid);
! 
!                                       row->refname = strdup(buf);
  
!                                       plpgsql_adddatum((PLpgSQL_datum *) row);
!                                       plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, 
row->rowno,
!                                                                          
row->refname);
  
-                                       arg_varnos[i] = row->rowno;
-                               }
-                               else
-                               {
                                        /*
!                                        * Normal parameters get a var node
                                         */
!                                       var = malloc(sizeof(PLpgSQL_var));
!                                       memset(var, 0, sizeof(PLpgSQL_var));
  
!                                       var->dtype = PLPGSQL_DTYPE_VAR;
!                                       var->refname = strdup(buf);
!                                       var->lineno = 0;
!                                       var->datatype = build_datatype(typeTup, -1);
!                                       var->isconst = true;
!                                       var->notnull = false;
!                                       var->default_val = NULL;
! 
!                                       plpgsql_adddatum((PLpgSQL_datum *) var);
!                                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, 
var->varno,
!                                                                          
var->refname);
  
!                                       arg_varnos[i] = var->varno;
                                }
!                               ReleaseSysCache(typeTup);
!                       }
!                       break;
  
!               case T_TRIGGER:
  
!                       /*
!                        * Trigger procedures return type is unknown yet
!                        */
!                       function->fn_rettype = InvalidOid;
!                       function->fn_retbyval = false;
!                       function->fn_retistuple = true;
!                       function->fn_retset = false;
  
!                       /*
!                        * Add the record for referencing NEW
!                        */
!                       rec = malloc(sizeof(PLpgSQL_rec));
!                       memset(rec, 0, sizeof(PLpgSQL_rec));
!                       rec->dtype = PLPGSQL_DTYPE_REC;
!                       rec->refname = strdup("new");
!                       rec->tup = NULL;
!                       rec->tupdesc = NULL;
!                       rec->freetup = false;
!                       plpgsql_adddatum((PLpgSQL_datum *) rec);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, 
rec->refname);
!                       function->new_varno = rec->recno;
  
!                       /*
!                        * Add the record for referencing OLD
!                        */
!                       rec = malloc(sizeof(PLpgSQL_rec));
!                       memset(rec, 0, sizeof(PLpgSQL_rec));
!                       rec->dtype = PLPGSQL_DTYPE_REC;
!                       rec->refname = strdup("old");
!                       rec->tup = NULL;
!                       rec->tupdesc = NULL;
!                       rec->freetup = false;
!                       plpgsql_adddatum((PLpgSQL_datum *) rec);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, 
rec->refname);
!                       function->old_varno = rec->recno;
  
!                       /*
!                        * Add the variable tg_name
!                        */
!                       var = malloc(sizeof(PLpgSQL_var));
!                       memset(var, 0, sizeof(PLpgSQL_var));
  
!                       var->dtype = PLPGSQL_DTYPE_VAR;
!                       var->refname = strdup("tg_name");
!                       var->lineno = 0;
!                       var->datatype = plpgsql_parse_datatype("name");
!                       var->isconst = false;
!                       var->notnull = false;
!                       var->default_val = NULL;
! 
!                       plpgsql_adddatum((PLpgSQL_datum *) var);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                       function->tg_name_varno = var->varno;
  
!                       /*
!                        * Add the variable tg_when
!                        */
!                       var = malloc(sizeof(PLpgSQL_var));
!                       memset(var, 0, sizeof(PLpgSQL_var));
  
!                       var->dtype = PLPGSQL_DTYPE_VAR;
!                       var->refname = strdup("tg_when");
!                       var->lineno = 0;
!                       var->datatype = plpgsql_parse_datatype("text");
!                       var->isconst = false;
!                       var->notnull = false;
!                       var->default_val = NULL;
! 
!                       plpgsql_adddatum((PLpgSQL_datum *) var);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                       function->tg_when_varno = var->varno;
  
!                       /*
!                        * Add the variable tg_level
!                        */
!                       var = malloc(sizeof(PLpgSQL_var));
!                       memset(var, 0, sizeof(PLpgSQL_var));
  
!                       var->dtype = PLPGSQL_DTYPE_VAR;
!                       var->refname = strdup("tg_level");
!                       var->lineno = 0;
!                       var->datatype = plpgsql_parse_datatype("text");
!                       var->isconst = false;
!                       var->notnull = false;
!                       var->default_val = NULL;
! 
!                       plpgsql_adddatum((PLpgSQL_datum *) var);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                       function->tg_level_varno = var->varno;
  
!                       /*
!                        * Add the variable tg_op
!                        */
!                       var = malloc(sizeof(PLpgSQL_var));
!                       memset(var, 0, sizeof(PLpgSQL_var));
  
!                       var->dtype = PLPGSQL_DTYPE_VAR;
!                       var->refname = strdup("tg_op");
!                       var->lineno = 0;
!                       var->datatype = plpgsql_parse_datatype("text");
!                       var->isconst = false;
!                       var->notnull = false;
!                       var->default_val = NULL;
! 
!                       plpgsql_adddatum((PLpgSQL_datum *) var);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                       function->tg_op_varno = var->varno;
  
!                       /*
!                        * Add the variable tg_relid
!                        */
!                       var = malloc(sizeof(PLpgSQL_var));
!                       memset(var, 0, sizeof(PLpgSQL_var));
  
!                       var->dtype = PLPGSQL_DTYPE_VAR;
!                       var->refname = strdup("tg_relid");
!                       var->lineno = 0;
!                       var->datatype = plpgsql_parse_datatype("oid");
!                       var->isconst = false;
!                       var->notnull = false;
!                       var->default_val = NULL;
! 
!                       plpgsql_adddatum((PLpgSQL_datum *) var);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                       function->tg_relid_varno = var->varno;
  
!                       /*
!                        * Add the variable tg_relname
!                        */
!                       var = malloc(sizeof(PLpgSQL_var));
!                       memset(var, 0, sizeof(PLpgSQL_var));
  
!                       var->dtype = PLPGSQL_DTYPE_VAR;
!                       var->refname = strdup("tg_relname");
!                       var->lineno = 0;
!                       var->datatype = plpgsql_parse_datatype("name");
!                       var->isconst = false;
!                       var->notnull = false;
!                       var->default_val = NULL;
! 
!                       plpgsql_adddatum((PLpgSQL_datum *) var);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                       function->tg_relname_varno = var->varno;
  
!                       /*
!                        * Add the variable tg_nargs
!                        */
!                       var = malloc(sizeof(PLpgSQL_var));
!                       memset(var, 0, sizeof(PLpgSQL_var));
  
!                       var->dtype = PLPGSQL_DTYPE_VAR;
!                       var->refname = strdup("tg_nargs");
!                       var->lineno = 0;
!                       var->datatype = plpgsql_parse_datatype("int4");
!                       var->isconst = false;
!                       var->notnull = false;
!                       var->default_val = NULL;
! 
!                       plpgsql_adddatum((PLpgSQL_datum *) var);
!                       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                       function->tg_nargs_varno = var->varno;
  
!                       break;
  
!               default:
!                       elog(ERROR, "unknown function type %u in plpgsql_compile()",
!                                functype);
!                       break;
!       }
  
!       /*
!        * Create the magic FOUND variable.
!        */
!       var = malloc(sizeof(PLpgSQL_var));
!       memset(var, 0, sizeof(PLpgSQL_var));
  
!       var->dtype = PLPGSQL_DTYPE_VAR;
!       var->refname = strdup("found");
!       var->lineno = 0;
!       var->datatype = plpgsql_parse_datatype("bool");
!       var->isconst = false;
!       var->notnull = false;
!       var->default_val = NULL;
  
!       plpgsql_adddatum((PLpgSQL_datum *) var);
!       plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
!       function->found_varno = var->varno;
  
!       /*
!        * Forget about the above created variables
!        */
!       plpgsql_add_initdatums(NULL);
  
!       /*
!        * Now parse the functions text
!        */
!       parse_rc = plpgsql_yyparse();
!       if (parse_rc != 0)
!               elog(ERROR, "plpgsql: parser returned %d ???", parse_rc);
  
!       plpgsql_scanner_finish();
  
!       /*
!        * If that was successful, complete the functions info.
!        */
!       function->fn_nargs = procStruct->pronargs;
!       for (i = 0; i < function->fn_nargs; i++)
!               function->fn_argvarnos[i] = arg_varnos[i];
!       function->ndatums = plpgsql_nDatums;
!       function->datums = malloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
!       for (i = 0; i < plpgsql_nDatums; i++)
!               function->datums[i] = plpgsql_Datums[i];
!       function->action = plpgsql_yylval.program;
  
        ReleaseSysCache(procTup);
  
        /*
!        * Pop the error context stack
         */
!       error_context_stack = plerrcontext.previous;
!       plpgsql_error_funcname = NULL;
!       plpgsql_error_lineno = 0;
  
        /*
         * Finally return the compiled function
         */
        if (plpgsql_DumpExecTree)
                plpgsql_dumptree(function);
        return function;
  }
  
--- 153,625 ----
        int                     i;
        int                     arg_varnos[FUNC_MAX_ARGS];
        ErrorContextCallback plerrcontext;
+       Oid                     rettypeid;
+       Oid                     funcOid = fcinfo->flinfo->fn_oid;
+       int                     functype = CALLED_AS_TRIGGER(fcinfo) ? T_TRIGGER : 
T_FUNCTION;
  
        /*
!        * Lookup the pg_proc tuple by Oid; we'll need it in any case
         */
        procTup = SearchSysCache(PROCOID,
!                                                        ObjectIdGetDatum(funcOid),
                                                         0, 0, 0);
        if (!HeapTupleIsValid(procTup))
!               elog(ERROR, "plpgsql: cache lookup for proc %u failed", funcOid);
  
        /*
!        * Lookup the function in the hashtable based on funcOid and
!        * argument type signature. Create the hash table if this
!        * is the first time through.
         */
!       function = get_function_by_signature(fcinfo, procTup);
  
        /*
!        * if the function wasn't found or was out-of-date,
!        * we have to compile it
         */
!       if (!function)
!       {
!               /*
!                * Setup the scanner input and error info.  We assume that this 
function
!                * cannot be invoked recursively, so there's no need to save and 
restore
!                * the static variables used here.
!                */
!               procStruct = (Form_pg_proc) GETSTRUCT(procTup);
!               proc_source = DatumGetCString(DirectFunctionCall1(textout,
!                                                                         
PointerGetDatum(&procStruct->prosrc)));
!               plpgsql_scanner_init(proc_source, functype);
!               pfree(proc_source);
  
!               plpgsql_error_funcname = pstrdup(NameStr(procStruct->proname));
!               plpgsql_error_lineno = 0;
  
!               /*
!                * Setup error traceback support for ereport()
!                */
!               plerrcontext.callback = plpgsql_compile_error_callback;
!               plerrcontext.arg = NULL;
!               plerrcontext.previous = error_context_stack;
!               error_context_stack = &plerrcontext;
  
!               /*
!                * Initialize the compiler
!                */
!               plpgsql_ns_init();
!               plpgsql_ns_push(NULL);
!               plpgsql_DumpExecTree = 0;
! 
!               datums_alloc = 128;
!               plpgsql_nDatums = 0;
!               plpgsql_Datums = palloc(sizeof(PLpgSQL_datum *) * datums_alloc);
!               datums_last = 0;
  
!               /*
!                * Create the new function node
!                */
!               function = malloc(sizeof(PLpgSQL_function));
!               memset(function, 0, sizeof(PLpgSQL_function));
!               plpgsql_curr_compile = function;
! 
!               function->fn_name = strdup(NameStr(procStruct->proname));
!               function->fn_oid = funcOid;
!               function->fn_xmin = HeapTupleHeaderGetXmin(procTup->t_data);
!               function->fn_cmin = HeapTupleHeaderGetCmin(procTup->t_data);
!               function->fn_functype = functype;
  
!               switch (functype)
!               {
!                       case T_FUNCTION:
  
!                               /*
!                                * Check for a polymorphic returntype. If found, use 
the actual
!                                * returntype type 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))
!                                               elog(ERROR, "could not determine 
actual return type " \
!                                                                       "for 
polymorphic function %s",
!                                                                       
plpgsql_error_funcname);
!                               }
                                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
!                               {
!                                       function->fn_retbyval = typeStruct->typbyval;
!                                       function->fn_rettyplen = typeStruct->typlen;
!                                       function->fn_rettypelem = typeStruct->typelem;
!                                       perm_fmgr_info(typeStruct->typinput, 
&(function->fn_retinput));
!                               }
!                               ReleaseSysCache(typeTup);
  
!                               /*
!                                * Create the variables for the procedures parameters
!                                */
!                               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))
!                                                       elog(ERROR, "could not 
determine actual argument " \
!                                                                               "type 
for polymorphic function %s",
!                                                                               
plpgsql_error_funcname);
!                                       }
!                                       else
!                                               argtypeid = procStruct->proargtypes[i];
  
!                                       function->fn_argtypes[i] = argtypeid;
  
                                        /*
!                                        * 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)
!                                       {
!                                               /*
!                                                * For tuple type parameters, we set 
up a record of
!                                                * that type
!                                                */
!                                               row = 
plpgsql_build_rowtype(typeStruct->typrelid);
! 
!                                               row->refname = strdup(buf);
! 
!                                               plpgsql_adddatum((PLpgSQL_datum *) 
row);
!                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_ROW, 
row->rowno,
!                                                                                  
row->refname);
! 
!                                               arg_varnos[i] = row->rowno;
!                                       }
!                                       else
!                                       {
!                                               /*
!                                                * Normal parameters get a var node
!                                                */
!                                               var = malloc(sizeof(PLpgSQL_var));
!                                               memset(var, 0, sizeof(PLpgSQL_var));
! 
!                                               var->dtype = PLPGSQL_DTYPE_VAR;
!                                               var->refname = strdup(buf);
!                                               var->lineno = 0;
!                                               var->datatype = 
build_datatype(typeTup, -1);
!                                               var->isconst = true;
!                                               var->notnull = false;
!                                               var->default_val = NULL;
! 
!                                               plpgsql_adddatum((PLpgSQL_datum *) 
var);
!                                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, 
var->varno,
!                                                                                  
var->refname);
  
!                                               arg_varnos[i] = var->varno;
!                                       }
!                                       ReleaseSysCache(typeTup);
                                }
!                               break;
  
!                       case T_TRIGGER:
  
!                               /*
!                                * Trigger procedures return type is unknown yet
!                                */
!                               function->fn_rettype = InvalidOid;
!                               function->fn_retbyval = false;
!                               function->fn_retistuple = true;
!                               function->fn_retset = false;
  
!                               /*
!                                * Add the record for referencing NEW
!                                */
!                               rec = malloc(sizeof(PLpgSQL_rec));
!                               memset(rec, 0, sizeof(PLpgSQL_rec));
!                               rec->dtype = PLPGSQL_DTYPE_REC;
!                               rec->refname = strdup("new");
!                               rec->tup = NULL;
!                               rec->tupdesc = NULL;
!                               rec->freetup = false;
!                               plpgsql_adddatum((PLpgSQL_datum *) rec);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, 
rec->refname);
!                               function->new_varno = rec->recno;
  
!                               /*
!                                * Add the record for referencing OLD
!                                */
!                               rec = malloc(sizeof(PLpgSQL_rec));
!                               memset(rec, 0, sizeof(PLpgSQL_rec));
!                               rec->dtype = PLPGSQL_DTYPE_REC;
!                               rec->refname = strdup("old");
!                               rec->tup = NULL;
!                               rec->tupdesc = NULL;
!                               rec->freetup = false;
!                               plpgsql_adddatum((PLpgSQL_datum *) rec);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_REC, rec->recno, 
rec->refname);
!                               function->old_varno = rec->recno;
  
!                               /*
!                                * Add the variable tg_name
!                                */
!                               var = malloc(sizeof(PLpgSQL_var));
!                               memset(var, 0, sizeof(PLpgSQL_var));
  
!                               var->dtype = PLPGSQL_DTYPE_VAR;
!                               var->refname = strdup("tg_name");
!                               var->lineno = 0;
!                               var->datatype = plpgsql_parse_datatype("name");
!                               var->isconst = false;
!                               var->notnull = false;
!                               var->default_val = NULL;
! 
!                               plpgsql_adddatum((PLpgSQL_datum *) var);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                               function->tg_name_varno = var->varno;
  
!                               /*
!                                * Add the variable tg_when
!                                */
!                               var = malloc(sizeof(PLpgSQL_var));
!                               memset(var, 0, sizeof(PLpgSQL_var));
  
!                               var->dtype = PLPGSQL_DTYPE_VAR;
!                               var->refname = strdup("tg_when");
!                               var->lineno = 0;
!                               var->datatype = plpgsql_parse_datatype("text");
!                               var->isconst = false;
!                               var->notnull = false;
!                               var->default_val = NULL;
! 
!                               plpgsql_adddatum((PLpgSQL_datum *) var);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                               function->tg_when_varno = var->varno;
  
!                               /*
!                                * Add the variable tg_level
!                                */
!                               var = malloc(sizeof(PLpgSQL_var));
!                               memset(var, 0, sizeof(PLpgSQL_var));
  
!                               var->dtype = PLPGSQL_DTYPE_VAR;
!                               var->refname = strdup("tg_level");
!                               var->lineno = 0;
!                               var->datatype = plpgsql_parse_datatype("text");
!                               var->isconst = false;
!                               var->notnull = false;
!                               var->default_val = NULL;
! 
!                               plpgsql_adddatum((PLpgSQL_datum *) var);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                               function->tg_level_varno = var->varno;
  
!                               /*
!                                * Add the variable tg_op
!                                */
!                               var = malloc(sizeof(PLpgSQL_var));
!                               memset(var, 0, sizeof(PLpgSQL_var));
  
!                               var->dtype = PLPGSQL_DTYPE_VAR;
!                               var->refname = strdup("tg_op");
!                               var->lineno = 0;
!                               var->datatype = plpgsql_parse_datatype("text");
!                               var->isconst = false;
!                               var->notnull = false;
!                               var->default_val = NULL;
! 
!                               plpgsql_adddatum((PLpgSQL_datum *) var);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                               function->tg_op_varno = var->varno;
  
!                               /*
!                                * Add the variable tg_relid
!                                */
!                               var = malloc(sizeof(PLpgSQL_var));
!                               memset(var, 0, sizeof(PLpgSQL_var));
  
!                               var->dtype = PLPGSQL_DTYPE_VAR;
!                               var->refname = strdup("tg_relid");
!                               var->lineno = 0;
!                               var->datatype = plpgsql_parse_datatype("oid");
!                               var->isconst = false;
!                               var->notnull = false;
!                               var->default_val = NULL;
! 
!                               plpgsql_adddatum((PLpgSQL_datum *) var);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                               function->tg_relid_varno = var->varno;
  
!                               /*
!                                * Add the variable tg_relname
!                                */
!                               var = malloc(sizeof(PLpgSQL_var));
!                               memset(var, 0, sizeof(PLpgSQL_var));
  
!                               var->dtype = PLPGSQL_DTYPE_VAR;
!                               var->refname = strdup("tg_relname");
!                               var->lineno = 0;
!                               var->datatype = plpgsql_parse_datatype("name");
!                               var->isconst = false;
!                               var->notnull = false;
!                               var->default_val = NULL;
! 
!                               plpgsql_adddatum((PLpgSQL_datum *) var);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                               function->tg_relname_varno = var->varno;
  
!                               /*
!                                * Add the variable tg_nargs
!                                */
!                               var = malloc(sizeof(PLpgSQL_var));
!                               memset(var, 0, sizeof(PLpgSQL_var));
  
!                               var->dtype = PLPGSQL_DTYPE_VAR;
!                               var->refname = strdup("tg_nargs");
!                               var->lineno = 0;
!                               var->datatype = plpgsql_parse_datatype("int4");
!                               var->isconst = false;
!                               var->notnull = false;
!                               var->default_val = NULL;
! 
!                               plpgsql_adddatum((PLpgSQL_datum *) var);
!                               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, 
var->refname);
!                               function->tg_nargs_varno = var->varno;
  
!                               break;
  
!                       default:
!                               elog(ERROR, "unknown function type %u in 
plpgsql_compile()",
!                                        functype);
!                               break;
!               }
  
!               /*
!                * Create the magic FOUND variable.
!                */
!               var = malloc(sizeof(PLpgSQL_var));
!               memset(var, 0, sizeof(PLpgSQL_var));
  
!               var->dtype = PLPGSQL_DTYPE_VAR;
!               var->refname = strdup("found");
!               var->lineno = 0;
!               var->datatype = plpgsql_parse_datatype("bool");
!               var->isconst = false;
!               var->notnull = false;
!               var->default_val = NULL;
  
!               plpgsql_adddatum((PLpgSQL_datum *) var);
!               plpgsql_ns_additem(PLPGSQL_NSTYPE_VAR, var->varno, var->refname);
!               function->found_varno = var->varno;
  
!               /*
!                * Forget about the above created variables
!                */
!               plpgsql_add_initdatums(NULL);
  
!               /*
!                * Now parse the functions text
!                */
!               parse_rc = plpgsql_yyparse();
!               if (parse_rc != 0)
!                       elog(ERROR, "plpgsql: parser returned %d ???", parse_rc);
  
!               plpgsql_scanner_finish();
  
!               /*
!                * If that was successful, complete the functions info.
!                */
!               function->fn_nargs = procStruct->pronargs;
!               for (i = 0; i < function->fn_nargs; i++)
!                       function->fn_argvarnos[i] = arg_varnos[i];
!               function->ndatums = plpgsql_nDatums;
!               function->datums = malloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
!               for (i = 0; i < plpgsql_nDatums; i++)
!                       function->datums[i] = plpgsql_Datums[i];
!               function->action = plpgsql_yylval.program;
! 
!               /*
!                * add it to the hash table
!                */
!               plpgsql_HashTableInsert(function);
! 
!               /*
!                * Pop the error context stack
!                */
!               error_context_stack = plerrcontext.previous;
!               plpgsql_error_funcname = NULL;
!               plpgsql_error_lineno = 0;
!       }
  
        ReleaseSysCache(procTup);
  
        /*
!        * Save pointer in FmgrInfo to avoid search on subsequent calls
         */
!       fcinfo->flinfo->fn_extra = (void *) function;
  
        /*
         * Finally return the compiled function
         */
        if (plpgsql_DumpExecTree)
                plpgsql_dumptree(function);
+ 
        return function;
  }
  
***************
*** 1500,1502 ****
--- 1595,1767 ----
        plpgsql_error_lineno = plpgsql_scanner_lineno();
        elog(ERROR, "%s at or near \"%s\"", s, plpgsql_yytext);
  }
+ 
+ 
+ /*
+  * get_function_by_signature
+  *
+  * Returns a function keyed by funcOid and argument types, or NULL
+  * if not found. Also checks to be sure what we found is still
+  * valid, clearing the hash table entry and returning NULL if it
+  * is out-of-date. This is needed because CREATE OR REPLACE FUNCTION
+  * can modify the function's pg_proc entry without changing its OID
+  * or arguments.
+  *
+  * Creates the hashtable if it doesn't already exist.
+  */
+ static PLpgSQL_function *
+ get_function_by_signature(FunctionCallInfo fcinfo, HeapTuple procTup)
+ {
+       PLpgSQL_function   *function = NULL;
+       PLpgSQL_func_key   *func_key;
+       Oid                                     funcOid = fcinfo->flinfo->fn_oid;
+       Form_pg_proc            procStruct = (Form_pg_proc) GETSTRUCT(procTup);
+       int                                     i;
+       bool                            entry_valid;
+ 
+       /*
+        * first see if we've already been here during the current
+        * SQL function call
+        */
+       function = (PLpgSQL_function *) fcinfo->flinfo->fn_extra;
+ 
+       if (!function)
+       {
+               if (!plpgsql_HashTable)
+                       plpgsql_HashTableInit();
+ 
+               func_key = (PLpgSQL_func_key *) palloc0(sizeof(PLpgSQL_func_key));
+               func_key->funcOid = funcOid;
+ 
+               /* get the argument types */
+               for (i = 0; i < procStruct->pronargs; i++)
+               {
+                       Oid                     argtypeid = InvalidOid;
+ 
+                       /*
+                        * 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))
+                                       elog(ERROR, "could not determine actual 
argument " \
+                                                               "type for polymorphic 
function %s",
+                                                               
plpgsql_error_funcname);
+                       }
+                       else
+                               argtypeid = procStruct->proargtypes[i];
+ 
+                       func_key->argtypes[i] = argtypeid;
+               }
+ 
+               function = plpgsql_HashTableLookup(func_key);
+       }
+ 
+       if (function)
+       {
+               /* we have a compiled function, but is it still valid */
+               entry_valid = 
+                       (function->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) 
&&
+                        function->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));
+ 
+               if (!entry_valid)
+               {
+                       plpgsql_HashTableDelete(function);
+ 
+                       /* XXX: is it worth worrying about the leaked function struct? 
*/
+                       function = NULL;
+               }
+       }
+ 
+       return function;
+ }
+ 
+ static void
+ plpgsql_HashTableInit(void)
+ {
+       HASHCTL         ctl;
+ 
+       memset(&ctl, 0, sizeof(ctl));
+       ctl.keysize = sizeof(PLpgSQL_func_key);
+       ctl.entrysize = sizeof(plpgsql_HashEnt);
+       ctl.hash = tag_hash;
+       plpgsql_HashTable = hash_create("PLpgSQL func cache", FUNCS_PER_USER,
+                                                                               &ctl, 
HASH_ELEM | HASH_FUNCTION);
+ }
+ 
+ static PLpgSQL_function *
+ plpgsql_HashTableLookup(PLpgSQL_func_key *func_key)
+ {
+       plpgsql_HashEnt    *hentry;
+ 
+       hentry = (plpgsql_HashEnt*) hash_search(plpgsql_HashTable,
+                                                                                      
 (void *) func_key,
+                                                                                      
 HASH_FIND,
+                                                                                      
 NULL);
+ 
+       if (hentry)
+               return hentry->function;
+       else
+               return (PLpgSQL_function *) NULL;
+ }
+ 
+ static void
+ plpgsql_HashTableInsert(PLpgSQL_function *function)
+ {
+       plpgsql_HashEnt    *hentry;
+       bool                            found;
+       PLpgSQL_func_key   *func_key;
+ 
+       func_key = function_get_func_key(function);
+       hentry = (plpgsql_HashEnt*) hash_search(plpgsql_HashTable,
+                                                                                      
 (void *) func_key,
+                                                                                      
 HASH_ENTER,
+                                                                                      
 &found);
+ 
+       if (hentry == NULL)
+               elog(ERROR, "out of memory in plpgsql_HashTable");
+ 
+       if (found)
+               elog(WARNING, "trying to insert a function that exists.");
+ 
+       hentry->function = function;
+ }
+ 
+ static void
+ plpgsql_HashTableDelete(PLpgSQL_function *function)
+ {
+       plpgsql_HashEnt    *hentry;
+       PLpgSQL_func_key   *func_key;
+ 
+       func_key = function_get_func_key(function);
+       hentry = (plpgsql_HashEnt*) hash_search(plpgsql_HashTable,
+                                                                                      
 (void *) func_key,
+                                                                                      
 HASH_REMOVE,
+                                                                                      
 NULL);
+ 
+       if (hentry == NULL)
+               elog(WARNING, "trying to delete function that does not exist.");
+ }
+ 
+ static PLpgSQL_func_key *
+ function_get_func_key(PLpgSQL_function *function)
+ {
+       PLpgSQL_func_key   *func_key;
+       int                                     i;
+ 
+       Assert(function != NULL);
+ 
+       func_key = (PLpgSQL_func_key *) palloc0(sizeof(PLpgSQL_func_key));
+       func_key->funcOid = function->fn_oid;
+ 
+       /* get the argument types */
+       for (i = 0; i < function->fn_nargs; i++)
+               func_key->argtypes[i] = function->fn_argtypes[i];
+ 
+       return func_key;
+ }
+ 
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 21:35:11 -0000
***************
*** 44,59 ****
  #include "utils/builtins.h"
  #include "utils/syscache.h"
  
- 
- /*
-  * Head of list of already-compiled functions
-  */
- static PLpgSQL_function *compiled_functions = NULL;
- 
- 
- static bool func_up_to_date(PLpgSQL_function * func);
- 
- 
  /* ----------
   * plpgsql_call_handler
   *
--- 44,49 ----
***************
*** 67,76 ****
  Datum
  plpgsql_call_handler(PG_FUNCTION_ARGS)
  {
-       bool            isTrigger = CALLED_AS_TRIGGER(fcinfo);
-       Oid                     funcOid = fcinfo->flinfo->fn_oid;
        PLpgSQL_function *func;
        Datum           retval;
  
        /*
         * Connect to SPI manager
--- 57,65 ----
  Datum
  plpgsql_call_handler(PG_FUNCTION_ARGS)
  {
        PLpgSQL_function *func;
        Datum           retval;
+       bool            isTrigger = CALLED_AS_TRIGGER(fcinfo);
  
        /*
         * Connect to SPI manager
***************
*** 78,126 ****
        if (SPI_connect() != SPI_OK_CONNECT)
                elog(ERROR, "plpgsql: cannot connect to SPI manager");
  
!       /*
!        * Check if we already compiled this function and saved the pointer
!        * (ie, current FmgrInfo has been used before)
!        */
!       func = (PLpgSQL_function *) fcinfo->flinfo->fn_extra;
!       if (func != NULL)
!       {
!               Assert(func->fn_oid == funcOid);
! 
!               /*
!                * But is the function still up to date?
!                */
!               if (!func_up_to_date(func))
!                       func = NULL;
!       }
! 
!       if (func == NULL)
!       {
!               /*
!                * Check if we already compiled this function for another caller
!                */
!               for (func = compiled_functions; func != NULL; func = func->next)
!               {
!                       if (funcOid == func->fn_oid && func_up_to_date(func))
!                               break;
!               }
! 
!               /*
!                * If not, do so and add it to the compiled ones
!                */
!               if (func == NULL)
!               {
!                       func = plpgsql_compile(funcOid,
!                                                                  isTrigger ? 
T_TRIGGER : T_FUNCTION);
!                       func->next = compiled_functions;
!                       compiled_functions = func;
!               }
! 
!               /*
!                * Save pointer in FmgrInfo to avoid search on subsequent calls
!                */
!               fcinfo->flinfo->fn_extra = (void *) func;
!       }
  
        /*
         * Determine if called as function or trigger and call appropriate
--- 67,74 ----
        if (SPI_connect() != SPI_OK_CONNECT)
                elog(ERROR, "plpgsql: cannot connect to SPI manager");
  
!       /* Find or compile the function */
!       func = plpgsql_compile(fcinfo);
  
        /*
         * Determine if called as function or trigger and call appropriate
***************
*** 139,169 ****
                elog(ERROR, "plpgsql: SPI_finish() failed");
  
        return retval;
- }
- 
- 
- /*
-  * 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;
- 
-       procTup = SearchSysCache(PROCOID,
-                                                        
ObjectIdGetDatum(func->fn_oid),
-                                                        0, 0, 0);
-       if (!HeapTupleIsValid(procTup))
-               elog(ERROR, "plpgsql: cache lookup for proc %u failed",
-                        func->fn_oid);
- 
-       result = (func->fn_xmin == HeapTupleHeaderGetXmin(procTup->t_data) &&
-                         func->fn_cmin == HeapTupleHeaderGetCmin(procTup->t_data));
- 
-       ReleaseSysCache(procTup);
- 
-       return result;
  }
--- 87,90 ----
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 21:28:42 -0000
***************
*** 504,509 ****
--- 504,510 ----
        bool            fn_retset;
  
        int                     fn_nargs;
+       Oid                     fn_argtypes[FUNC_MAX_ARGS];
        int                     fn_argvarnos[FUNC_MAX_ARGS];
        int                     found_varno;
        int                     new_varno;
***************
*** 519,526 ****
        int                     ndatums;
        PLpgSQL_datum **datums;
        PLpgSQL_stmt_block *action;
- 
-       struct PLpgSQL_function *next;          /* for chaining list of functions */
  }     PLpgSQL_function;
  
  
--- 520,525 ----
***************
*** 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);
--- 587,593 ----
   * Functions in pl_comp.c
   * ----------
   */
! extern PLpgSQL_function *plpgsql_compile(FunctionCallInfo fcinfo);
  extern int    plpgsql_parse_word(char *word);
  extern int    plpgsql_parse_dblword(char *word);
  extern int    plpgsql_parse_tripword(char *word);
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]

Reply via email to