88 *
99 *
1010 * IDENTIFICATION
11- * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.48 2001/03/22 06:16:17 momjian Exp $
11+ * $Header: /cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.49 2001/06/01 15:45:42 tgl Exp $
1212 *
1313 * NOTES
1414 * This cruft is the server side of PQfn.
5858 *
5959 *-------------------------------------------------------------------------
6060 */
61-
6261#include "postgres.h"
6362
6463#include "access/xact.h"
6564#include "catalog/pg_proc.h"
66- #include "catalog/pg_type.h"
6765#include "libpq/libpq.h"
6866#include "libpq/pqformat.h"
6967#include "tcop/fastpath.h"
68+ #include "utils/lsyscache.h"
7069#include "utils/syscache.h"
7170
7271
@@ -114,78 +113,38 @@ SendFunctionResult(Datum retval,/* actual return value */
114113}
115114
116115/*
117- * This structure saves enough state so that one can avoid having to
118- * do catalog lookups over and over again.(Each RPC can require up
119- * to FUNC_MAX_ARGS+2 lookups, which is quite tedious.)
120- *
121- * The previous incarnation of this code just assumed that any argument
122- * of size <= 4 was by value; this is not correct.There is no cheap
123- * way to determine function argument length etc.; one must simply pay
124- * the price of catalog lookups.
116+ * Formerly, this code attempted to cache the function and type info
117+ * looked up by fetch_fp_info, but only for the duration of a single
118+ * transaction command (since in theory the info could change between
119+ * commands). This was utterly useless, because postgres.c executes
120+ * each fastpath call as a separate transaction command, and so the
121+ * cached data could never actually have been reused. If it had worked
122+ * as intended, it would have had problems anyway with dangling references
123+ * in the FmgrInfo struct. So, forget about caching and just repeat the
124+ * syscache fetches on each usage. They're not *that* expensive.
125125 */
126126struct fp_info
127127{
128128Oid funcid ;
129129FmgrInfo flinfo ;/* function lookup info for funcid */
130+ int16 arglen [FUNC_MAX_ARGS ];
130131bool argbyval [FUNC_MAX_ARGS ];
131- int32 arglen [ FUNC_MAX_ARGS ]; /* signed (for varlena) */
132+ int16 retlen ;
132133bool retbyval ;
133- int32 retlen ;/* signed (for varlena) */
134- TransactionId xid ;/* when the lookup was done */
135- CommandId cid ;
136134};
137135
138136/*
139- * We implement one-back caching here.If we need to do more, we can.
140- * Most routines in tight loops (like PQfswrite -> F_LOWRITE) will do
141- * the same thing repeatedly.
142- */
143- static struct fp_info last_fp = {InvalidOid };
144-
145- /*
146- * valid_fp_info
147- *
148- * RETURNS:
149- *T if the state in 'fip' is valid for the given func OID
150- *F otherwise
151- *
152- * "invalid" means:
153- * The saved state was either uninitialized, for another function,
154- * or from a previous command.(Commands can do updates, which
155- * may invalidate catalog entries for subsequent commands.This
156- * is overly pessimistic but since there is no smarter invalidation
157- * scheme...).
158- */
159- static bool
160- valid_fp_info (Oid func_id ,struct fp_info * fip )
161- {
162- Assert (OidIsValid (func_id ));
163- Assert (fip != (struct fp_info * )NULL );
164-
165- return (OidIsValid (fip -> funcid )&&
166- func_id == fip -> funcid &&
167- TransactionIdIsCurrentTransactionId (fip -> xid )&&
168- CommandIdIsCurrentCommandId (fip -> cid ));
169- }
170-
171- /*
172- * update_fp_info
137+ * fetch_fp_info
173138 *
174139 * Performs catalog lookups to load a struct fp_info 'fip' for the
175140 * function 'func_id'.
176- *
177- * RETURNS:
178- *The correct information in 'fip'. Sets 'fip->funcid' to
179- *InvalidOid if an exception occurs.
180141 */
181142static void
182- update_fp_info (Oid func_id ,struct fp_info * fip )
143+ fetch_fp_info (Oid func_id ,struct fp_info * fip )
183144{
184145Oid * argtypes ;/* an oidvector */
185146Oid rettype ;
186- HeapTuple func_htp ,
187- type_htp ;
188- Form_pg_type tp ;
147+ HeapTuple func_htp ;
189148Form_pg_proc pp ;
190149int i ;
191150
@@ -197,56 +156,32 @@ update_fp_info(Oid func_id, struct fp_info * fip)
197156 * funcid is OK, we clear the funcid here.It must not be set to the
198157 * correct value until we are about to return with a good struct
199158 * fp_info, since we can be interrupted (i.e., with an elog(ERROR,
200- * ...)) at any time.
159+ * ...)) at any time. [No longer really an issue since we don't save
160+ * the struct fp_info across transactions anymore, but keep it anyway.]
201161 */
202- MemSet ((char * )fip ,0 ,( int ) sizeof (struct fp_info ));
162+ MemSet ((char * )fip ,0 ,sizeof (struct fp_info ));
203163fip -> funcid = InvalidOid ;
204164
165+ fmgr_info (func_id ,& fip -> flinfo );
166+
205167func_htp = SearchSysCache (PROCOID ,
206168ObjectIdGetDatum (func_id ),
2071690 ,0 ,0 );
208170if (!HeapTupleIsValid (func_htp ))
209- elog (ERROR ,"update_fp_info : cache lookup for function %u failed" ,
171+ elog (ERROR ,"fetch_fp_info : cache lookup for function %u failed" ,
210172func_id );
211173pp = (Form_pg_proc )GETSTRUCT (func_htp );
212174rettype = pp -> prorettype ;
213175argtypes = pp -> proargtypes ;
214176
215- fmgr_info (func_id ,& fip -> flinfo );
216-
217- for (i = 0 ;i < fip -> flinfo .fn_nargs ;++ i )
177+ for (i = 0 ;i < pp -> pronargs ;++ i )
218178{
219179if (OidIsValid (argtypes [i ]))
220- {
221- type_htp = SearchSysCache (TYPEOID ,
222- ObjectIdGetDatum (argtypes [i ]),
223- 0 ,0 ,0 );
224- if (!HeapTupleIsValid (type_htp ))
225- elog (ERROR ,"update_fp_info: bad argument type %u for %u" ,
226- argtypes [i ],func_id );
227- tp = (Form_pg_type )GETSTRUCT (type_htp );
228- fip -> argbyval [i ]= tp -> typbyval ;
229- fip -> arglen [i ]= tp -> typlen ;
230- ReleaseSysCache (type_htp );
231- }/* else it had better be VAR_LENGTH_ARG */
180+ get_typlenbyval (argtypes [i ],& fip -> arglen [i ],& fip -> argbyval [i ]);
232181}
233182
234183if (OidIsValid (rettype ))
235- {
236- type_htp = SearchSysCache (TYPEOID ,
237- ObjectIdGetDatum (rettype ),
238- 0 ,0 ,0 );
239- if (!HeapTupleIsValid (type_htp ))
240- elog (ERROR ,"update_fp_info: bad return type %u for %u" ,
241- rettype ,func_id );
242- tp = (Form_pg_type )GETSTRUCT (type_htp );
243- fip -> retbyval = tp -> typbyval ;
244- fip -> retlen = tp -> typlen ;
245- ReleaseSysCache (type_htp );
246- }/* else it had better by VAR_LENGTH_RESULT */
247-
248- fip -> xid = GetCurrentTransactionId ();
249- fip -> cid = GetCurrentCommandId ();
184+ get_typlenbyval (rettype ,& fip -> retlen ,& fip -> retbyval );
250185
251186ReleaseSysCache (func_htp );
252187
@@ -286,6 +221,7 @@ HandleFunctionRequest(void)
286221Datum retval ;
287222int i ;
288223char * p ;
224+ struct fp_info my_fp ;
289225struct fp_info * fip ;
290226
291227/*
@@ -324,14 +260,11 @@ HandleFunctionRequest(void)
324260return EOF ;
325261
326262/*
327- * This is where the one-back caching is done. If you want to save
328- * more state, make this a loop around an array. Given the relatively
329- * short lifespan of the cache, not clear that there's any win
330- * possible.
263+ * There used to be a lame attempt at caching lookup info here.
264+ * Now we just do the lookups on every call.
331265 */
332- fip = & last_fp ;
333- if (!valid_fp_info (fid ,fip ))
334- update_fp_info (fid ,fip );
266+ fip = & my_fp ;
267+ fetch_fp_info (fid ,fip );
335268
336269if (fip -> flinfo .fn_nargs != nargs || nargs > FUNC_MAX_ARGS )
337270{