diff options
author | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
---|---|---|
committer | Marc G. Fournier <scrappy@hub.org> | 1996-07-09 06:22:35 +0000 |
commit | d31084e9d1118b25fd16580d9d8c2924b5740dff (patch) | |
tree | 3179e66307d54df9c7b966543550e601eb55e668 /src/backend/utils/cache/fcache.c | |
download | postgresql-PG95-1_01.tar.gz postgresql-PG95-1_01.zip |
Postgres95 1.01 Distribution - Virgin SourcesPG95-1_01
Diffstat (limited to 'src/backend/utils/cache/fcache.c')
-rw-r--r-- | src/backend/utils/cache/fcache.c | 297 |
1 files changed, 297 insertions, 0 deletions
diff --git a/src/backend/utils/cache/fcache.c b/src/backend/utils/cache/fcache.c new file mode 100644 index 00000000000..070f457c280 --- /dev/null +++ b/src/backend/utils/cache/fcache.c @@ -0,0 +1,297 @@ +/*------------------------------------------------------------------------- + * + * fcache.c-- + * Code for the 'function cache' used in Oper and Func nodes.... + * + * Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/backend/utils/cache/Attic/fcache.c,v 1.1.1.1 1996/07/09 06:22:06 scrappy Exp $ + * + *------------------------------------------------------------------------- + */ +#include "c.h" +#include "access/htup.h" +#include "utils/catcache.h" +#include "utils/syscache.h" +#include "catalog/pg_type.h" +#include "catalog/pg_proc.h" +#include "catalog/pg_language.h" +#include "catalog/pg_class.h" +#include "parser/parsetree.h" /* for getrelname() */ +#include "utils/builtins.h" +#include "utils/fcache.h" +#include "utils/elog.h" +#include "utils/palloc.h" +#include "nodes/primnodes.h" +#include "nodes/execnodes.h" + +static Oid GetDynamicFuncArgType(Var *arg, ExprContext *econtext); +static FunctionCachePtr init_fcache(Oid foid, + bool use_syscache, + List *argList, + ExprContext *econtext); + +/*----------------------------------------------------------------- + * + * Initialize the 'FunctionCache' given the PG_PROC oid. + * + * + * NOTE: This function can be called when the system cache is being + * initialized. Therefore, use_syscache should ONLY be true + * when the function return type is interesting (ie: set_fcache). + *----------------------------------------------------------------- + */ +#define FuncArgTypeIsDynamic(arg) \ + (IsA(arg,Var) && ((Var*)arg)->varattno == InvalidAttrNumber) + +static Oid +GetDynamicFuncArgType(Var *arg, ExprContext *econtext) +{ + char *relname; + int rtid; + HeapTuple tup; + + Assert(IsA(arg,Var)); + + rtid = ((Var*)arg)->varno; + relname = (char*)getrelname(rtid, econtext->ecxt_range_table); + + + tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(relname), + 0,0,0); + if (!tup) + elog(WARN, "Lookup failed on type tuple for class %s", + relname); + + return tup->t_oid; +} + +static FunctionCachePtr +init_fcache(Oid foid, + bool use_syscache, + List *argList, + ExprContext *econtext) +{ + HeapTuple procedureTuple; + HeapTuple typeTuple; + Form_pg_proc procedureStruct; + TypeTupleForm typeStruct; + FunctionCachePtr retval; + text *tmp; + int nargs; + + /* ---------------- + * get the procedure tuple corresponding to the given + * functionOid. If this fails, returnValue has been + * pre-initialized to "null" so we just return it. + * ---------------- + */ + retval = (FunctionCachePtr) palloc(sizeof(FunctionCache)); + + if (!use_syscache) + elog(WARN, "what the ????, init the fcache without the catalogs?"); + + procedureTuple = SearchSysCacheTuple(PROOID, + ObjectIdGetDatum(foid), + 0,0,0); + + if (!HeapTupleIsValid(procedureTuple)) + elog(WARN, + "init_fcache: %s %d", + "Cache lookup failed for procedure", foid); + + /* ---------------- + * get the return type from the procedure tuple + * ---------------- + */ + procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple); + + /* ---------------- + * get the type tuple corresponding to the return type + * If this fails, returnValue has been pre-initialized + * to "null" so we just return it. + * ---------------- + */ + typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(procedureStruct->prorettype), + 0,0,0); + + if (!HeapTupleIsValid(typeTuple)) + elog(WARN, + "init_fcache: %s %d", + "Cache lookup failed for type", + (procedureStruct)->prorettype); + + /* ---------------- + * get the type length and by-value from the type tuple and + * save the information in our one element cache. + * ---------------- + */ + typeStruct = (TypeTupleForm) GETSTRUCT(typeTuple); + + retval->typlen = (typeStruct)->typlen; + if ((typeStruct)->typrelid == InvalidOid) { + /* The return type is not a relation, so just use byval */ + retval->typbyval = (typeStruct)->typbyval ? true : false ; + } else { + /* This is a hack. We assume here that any function returning + * a relation returns it by reference. This needs to be + * fixed. + */ + retval->typbyval = false; + } + retval->foid = foid; + retval->language = procedureStruct->prolang; + retval->func_state = (char *)NULL; + retval->setArg = NULL; + retval->hasSetArg = false; + retval->oneResult = ! procedureStruct->proretset; + retval->istrusted = procedureStruct->proistrusted; + + /* + * If we are returning exactly one result then we have to copy + * tuples and by reference results because we have to end the execution + * before we return the results. When you do this everything allocated + * by the executor (i.e. slots and tuples) is freed. + */ + if ((retval->language == SQLlanguageId) && + (retval->oneResult) && + !(retval->typbyval)) + { + Form_pg_class relationStruct; + HeapTuple relationTuple; + TupleDesc td; + TupleTableSlot *slot; + + slot = makeNode(TupleTableSlot); + slot->ttc_shouldFree = true; + slot->ttc_descIsNew = true; + slot->ttc_tupleDescriptor = (TupleDesc) NULL; + slot->ttc_buffer = InvalidBuffer; + slot->ttc_whichplan = -1; + retval->funcSlot = (Pointer)slot; + + relationTuple = (HeapTuple) + SearchSysCacheTuple(RELNAME, + PointerGetDatum(&typeStruct->typname), + 0,0,0); + + if (relationTuple) + { + relationStruct = (Form_pg_class)GETSTRUCT(relationTuple); + td = CreateTemplateTupleDesc(relationStruct->relnatts); + } + else + td = CreateTemplateTupleDesc(1); + + ((TupleTableSlot*)retval->funcSlot)->ttc_tupleDescriptor = td; + } + else + retval->funcSlot = (char *)NULL; + + nargs = procedureStruct->pronargs; + retval->nargs = nargs; + + if (nargs > 0) + { + Oid *argTypes; + + retval->nullVect = (bool *)palloc((retval->nargs)*sizeof(bool)); + + if (retval->language == SQLlanguageId) + { + int i; + List *oneArg; + + retval->argOidVect = + (Oid *)palloc(retval->nargs*sizeof(Oid)); + argTypes = procedureStruct->proargtypes; + memmove(retval->argOidVect, + argTypes, + (retval->nargs)*sizeof(Oid)); + + for (i=0; + argList; + i++, argList = lnext(argList)) + { + oneArg = lfirst(argList); + if (FuncArgTypeIsDynamic(oneArg)) + retval->argOidVect[i] = GetDynamicFuncArgType((Var*)oneArg, + econtext); + } + } + else + retval->argOidVect = (Oid *)NULL; + } + else + { + retval->argOidVect = (Oid *)NULL; + retval->nullVect = (BoolPtr)NULL; + } + + /* + * XXX this is the first varlena in the struct. If the order + * changes for some reason this will fail. + */ + if (procedureStruct->prolang == SQLlanguageId) + { + retval->src = textout(&(procedureStruct->prosrc)); + retval->bin = (char *) NULL; + } + else + { + + /* + * I'm not sure that we even need to do this at all. + */ + + /* + * We do for untrusted functions. + */ + + if (procedureStruct->proistrusted) + retval->bin = (char *) NULL; + else { + tmp = (text *) + SearchSysCacheGetAttribute(PROOID, + Anum_pg_proc_probin, + ObjectIdGetDatum(foid), + 0,0,0); + retval->bin = textout(tmp); + } + retval->src = (char *) NULL; + } + + + + + if (retval->language != SQLlanguageId) + fmgr_info(foid, &(retval->func), &(retval->nargs)); + else + retval->func = (func_ptr)NULL; + + + return(retval); +} + +void +setFcache(Node *node, Oid foid, List *argList, ExprContext *econtext) +{ + Func *fnode; + Oper *onode; + FunctionCachePtr fcache; + + fcache = init_fcache(foid, true, argList, econtext); + + if (IsA(node,Oper)) { + onode = (Oper*) node; + onode->op_fcache = fcache; + }else if (IsA(node,Func)) { + fnode = (Func*) node; + fnode->func_fcache = fcache; + }else { + elog(WARN, "init_fcache: node must be Oper or Func!"); + } +} |