fastpath.c
上传用户:blenddy
上传日期:2007-01-07
资源大小:6495k
文件大小:10k
源码类别:

数据库系统

开发平台:

Unix_Linux

  1. /*-------------------------------------------------------------------------
  2.  *
  3.  * fastpath.c
  4.  *   routines to handle function requests from the frontend
  5.  *
  6.  * Copyright (c) 1994, Regents of the University of California
  7.  *
  8.  *
  9.  * IDENTIFICATION
  10.  *   $Header: /usr/local/cvsroot/pgsql/src/backend/tcop/fastpath.c,v 1.24 1999/05/10 00:45:46 momjian Exp $
  11.  *
  12.  * NOTES
  13.  *   This cruft is the server side of PQfn.
  14.  *
  15.  *   - jolly 07/11/95:
  16.  *
  17.  *   no longer rely on return sizes provided by the frontend. Always
  18.  *   use the true lengths for the catalogs.  Assume that the frontend
  19.  *   has allocated enough space to handle the result value returned.
  20.  *
  21.  *   trust that the user knows what he is doing with the args.  If the
  22.  *   sys catalog says it is a varlena, assume that the user is only sending
  23.  *   down VARDATA and that the argsize is the VARSIZE.  If the arg is
  24.  *   fixed len, assume that the argsize given by the user is correct.
  25.  *
  26.  *   if the function returns by value, then only send 4 bytes value
  27.  *   back to the frontend.  If the return returns by reference,
  28.  *   send down only the data portion and set the return size appropriately.
  29.  *
  30.  *  OLD COMMENTS FOLLOW
  31.  *
  32.  *   The VAR_LENGTH_{ARGS,RESULT} stuff is limited to MAX_STRING_LENGTH
  33.  *   (see src/backend/tmp/fastpath.h) for no obvious reason.  Since its
  34.  *   primary use (for us) is for Inversion path names, it should probably
  35.  *   be increased to 256 (MAXPATHLEN for Inversion, hidden in pg_type
  36.  *   as well as utils/adt/filename.c).
  37.  *
  38.  *   Quoth PMA on 08/15/93:
  39.  *
  40.  *   This code has been almost completely rewritten with an eye to
  41.  *   keeping it as compatible as possible with the previous (broken)
  42.  *   implementation.
  43.  *
  44.  *   The previous implementation would assume (1) that any value of
  45.  *   length <= 4 bytes was passed-by-value, and that any other value
  46.  *   was a struct varlena (by-reference). There was NO way to pass a
  47.  *   fixed-length by-reference argument (like name) or a struct
  48.  *   varlena of size <= 4 bytes.
  49.  *
  50.  *   The new implementation checks the catalogs to determine whether
  51.  *   a value is by-value (type "0" is null-delimited character string,
  52.  *   as it is for, e.g., the parser). The only other item obtained
  53.  *   from the catalogs is whether or not the value should be placed in
  54.  *   a struct varlena or not. Otherwise, the size given by the
  55.  *   frontend is assumed to be correct (probably a bad decision, but
  56.  *   we do strange things in the name of compatibility).
  57.  *
  58.  *-------------------------------------------------------------------------
  59.  */
  60. #include <string.h>
  61. #include "postgres.h"
  62. #include "tcop/tcopdebug.h"
  63. #include "utils/palloc.h"
  64. #include "fmgr.h"
  65. #include "utils/builtins.h" /* for oideq */
  66. #include "tcop/fastpath.h"
  67. #include "libpq/libpq.h"
  68. #include "libpq/pqformat.h"
  69. #include "access/xact.h" /* for TransactionId/CommandId protos */
  70. #include "utils/syscache.h"
  71. #include "catalog/pg_proc.h"
  72. #include "catalog/pg_type.h"
  73. /* ----------------
  74.  * SendFunctionResult
  75.  * ----------------
  76.  */
  77. static void
  78. SendFunctionResult(Oid fid, /* function id */
  79.    char *retval,/* actual return value */
  80.    bool retbyval,
  81.    int retlen /* the length according to the catalogs */
  82. )
  83. {
  84. StringInfoData buf;
  85. pq_beginmessage(&buf);
  86. pq_sendbyte(&buf, 'V');
  87. if (retlen != 0)
  88. {
  89. pq_sendbyte(&buf, 'G');
  90. if (retbyval)
  91. { /* by-value */
  92. pq_sendint(&buf, retlen, 4);
  93. pq_sendint(&buf, (int) (Datum) retval, retlen);
  94. }
  95. else
  96. { /* by-reference ... */
  97. if (retlen < 0)
  98. { /* ... varlena */
  99. pq_sendint(&buf, VARSIZE(retval) - VARHDRSZ, VARHDRSZ);
  100. pq_sendbytes(&buf, VARDATA(retval), VARSIZE(retval) - VARHDRSZ);
  101. }
  102. else
  103. { /* ... fixed */
  104. pq_sendint(&buf, retlen, 4);
  105. pq_sendbytes(&buf, retval, retlen);
  106. }
  107. }
  108. }
  109. pq_sendbyte(&buf, '0');
  110. pq_endmessage(&buf);
  111. }
  112. /*
  113.  * This structure saves enough state so that one can avoid having to
  114.  * do catalog lookups over and over again. (Each RPC can require up
  115.  * to MAXFMGRARGS+2 lookups, which is quite tedious.)
  116.  *
  117.  * The previous incarnation of this code just assumed that any argument
  118.  * of size <= 4 was by value; this is not correct. There is no cheap
  119.  * way to determine function argument length etc.; one must simply pay
  120.  * the price of catalog lookups.
  121.  */
  122. struct fp_info
  123. {
  124. Oid funcid;
  125. int nargs;
  126. bool argbyval[MAXFMGRARGS];
  127. int32 arglen[MAXFMGRARGS]; /* signed (for varlena) */
  128. bool retbyval;
  129. int32 retlen; /* signed (for varlena) */
  130. TransactionId xid;
  131. CommandId cid;
  132. };
  133. /*
  134.  * We implement one-back caching here. If we need to do more, we can.
  135.  * Most routines in tight loops (like PQfswrite -> F_LOWRITE) will do
  136.  * the same thing repeatedly.
  137.  */
  138. static struct fp_info last_fp = {InvalidOid};
  139. /*
  140.  * valid_fp_info
  141.  *
  142.  * RETURNS:
  143.  * 1 if the state in 'fip' is valid
  144.  * 0 otherwise
  145.  *
  146.  * "valid" means:
  147.  * The saved state was either uninitialized, for another function,
  148.  * or from a previous command. (Commands can do updates, which
  149.  * may invalidate catalog entries for subsequent commands. This
  150.  * is overly pessimistic but since there is no smarter invalidation
  151.  * scheme...).
  152.  */
  153. static int
  154. valid_fp_info(Oid func_id, struct fp_info * fip)
  155. {
  156. Assert(OidIsValid(func_id));
  157. Assert(fip != (struct fp_info *) NULL);
  158. return (OidIsValid(fip->funcid) &&
  159. oideq(func_id, fip->funcid) &&
  160. TransactionIdIsCurrentTransactionId(fip->xid) &&
  161. CommandIdIsCurrentCommandId(fip->cid));
  162. }
  163. /*
  164.  * update_fp_info
  165.  *
  166.  * Performs catalog lookups to load a struct fp_info 'fip' for the
  167.  * function 'func_id'.
  168.  *
  169.  * RETURNS:
  170.  * The correct information in 'fip'.  Sets 'fip->funcid' to
  171.  * InvalidOid if an exception occurs.
  172.  */
  173. static void
  174. update_fp_info(Oid func_id, struct fp_info * fip)
  175. {
  176. Oid    *argtypes; /* an oid8 */
  177. Oid rettype;
  178. HeapTuple func_htp,
  179. type_htp;
  180. Form_pg_type tp;
  181. Form_pg_proc pp;
  182. int i;
  183. Assert(OidIsValid(func_id));
  184. Assert(fip != (struct fp_info *) NULL);
  185. /*
  186.  * Since the validity of this structure is determined by whether the
  187.  * funcid is OK, we clear the funcid here. It must not be set to the
  188.  * correct value until we are about to return with a good struct
  189.  * fp_info, since we can be interrupted (i.e., with an elog(ERROR,
  190.  * ...)) at any time.
  191.  */
  192. MemSet((char *) fip, 0, (int) sizeof(struct fp_info));
  193. fip->funcid = InvalidOid;
  194. func_htp = SearchSysCacheTuple(PROOID,
  195.    ObjectIdGetDatum(func_id),
  196.    0, 0, 0);
  197. if (!HeapTupleIsValid(func_htp))
  198. {
  199. elog(ERROR, "update_fp_info: cache lookup for function %u failed",
  200.  func_id);
  201. }
  202. pp = (Form_pg_proc) GETSTRUCT(func_htp);
  203. fip->nargs = pp->pronargs;
  204. rettype = pp->prorettype;
  205. argtypes = pp->proargtypes;
  206. for (i = 0; i < fip->nargs; ++i)
  207. {
  208. if (OidIsValid(argtypes[i]))
  209. {
  210. type_htp = SearchSysCacheTuple(TYPOID,
  211.    ObjectIdGetDatum(argtypes[i]),
  212.    0, 0, 0);
  213. if (!HeapTupleIsValid(type_htp))
  214. {
  215. elog(ERROR, "update_fp_info: bad argument type %u for %u",
  216.  argtypes[i], func_id);
  217. }
  218. tp = (Form_pg_type) GETSTRUCT(type_htp);
  219. fip->argbyval[i] = tp->typbyval;
  220. fip->arglen[i] = tp->typlen;
  221. } /* else it had better be VAR_LENGTH_ARG */
  222. }
  223. if (OidIsValid(rettype))
  224. {
  225. type_htp = SearchSysCacheTuple(TYPOID,
  226.    ObjectIdGetDatum(rettype),
  227.    0, 0, 0);
  228. if (!HeapTupleIsValid(type_htp))
  229. {
  230. elog(ERROR, "update_fp_info: bad return type %u for %u",
  231.  rettype, func_id);
  232. }
  233. tp = (Form_pg_type) GETSTRUCT(type_htp);
  234. fip->retbyval = tp->typbyval;
  235. fip->retlen = tp->typlen;
  236. } /* else it had better by VAR_LENGTH_RESULT */
  237. fip->xid = GetCurrentTransactionId();
  238. fip->cid = GetCurrentCommandId();
  239. /*
  240.  * This must be last!
  241.  */
  242. fip->funcid = func_id;
  243. }
  244. /*
  245.  * HandleFunctionRequest
  246.  *
  247.  * Server side of PQfn (fastpath function calls from the frontend).
  248.  * This corresponds to the libpq protocol symbol "F".
  249.  *
  250.  * RETURNS:
  251.  * nothing of significance.
  252.  * All errors result in elog(ERROR,...).
  253.  */
  254. int
  255. HandleFunctionRequest()
  256. {
  257. Oid fid;
  258. int argsize;
  259. int nargs;
  260. int tmp;
  261. char    *arg[8];
  262. char    *retval;
  263. int i;
  264. uint32 palloced;
  265. char    *p;
  266. struct fp_info *fip;
  267. pq_getint(&tmp, 4); /* function oid */
  268. fid = (Oid) tmp;
  269. pq_getint(&nargs, 4); /* # of arguments */
  270. /*
  271.  * This is where the one-back caching is done. If you want to save
  272.  * more state, make this a loop around an array.
  273.  */
  274. fip = &last_fp;
  275. if (!valid_fp_info(fid, fip))
  276. update_fp_info(fid, fip);
  277. if (fip->nargs != nargs)
  278. {
  279. elog(ERROR, "HandleFunctionRequest: actual arguments (%d) != registered arguments (%d)",
  280.  nargs, fip->nargs);
  281. }
  282. /*
  283.  * Copy arguments into arg vector. If we palloc() an argument, we
  284.  * need to remember, so that we pfree() it after the call.
  285.  */
  286. palloced = 0x0;
  287. for (i = 0; i < 8; ++i)
  288. {
  289. if (i >= nargs)
  290. arg[i] = (char *) NULL;
  291. else
  292. {
  293. pq_getint(&argsize, 4);
  294. Assert(argsize > 0);
  295. if (fip->argbyval[i])
  296. { /* by-value */
  297. Assert(argsize <= 4);
  298. pq_getint(&tmp, argsize);
  299. arg[i] = (char *) tmp;
  300. }
  301. else
  302. { /* by-reference ... */
  303. if (fip->arglen[i] < 0)
  304. { /* ... varlena */
  305. if (!(p = palloc(argsize + VARHDRSZ + 1))) /* Added +1 to solve
  306.  * memory leak - Peter
  307.  * 98 Jan 6 */
  308. elog(ERROR, "HandleFunctionRequest: palloc failed");
  309. VARSIZE(p) = argsize + VARHDRSZ;
  310. pq_getbytes(VARDATA(p), argsize);
  311. }
  312. else
  313. { /* ... fixed */
  314. /* XXX cross our fingers and trust "argsize" */
  315. if (!(p = palloc(argsize + 1)))
  316. elog(ERROR, "HandleFunctionRequest: palloc failed");
  317. pq_getbytes(p, argsize);
  318. }
  319. palloced |= (1 << i);
  320. arg[i] = p;
  321. }
  322. }
  323. }
  324. #ifndef NO_FASTPATH
  325. retval = fmgr(fid,
  326.   arg[0], arg[1], arg[2], arg[3],
  327.   arg[4], arg[5], arg[6], arg[7]);
  328. #else
  329. retval = NULL;
  330. #endif  /* NO_FASTPATH */
  331. /* free palloc'ed arguments */
  332. for (i = 0; i < nargs; ++i)
  333. {
  334. if (palloced & (1 << i))
  335. pfree(arg[i]);
  336. }
  337. /*
  338.  * If this is an ordinary query (not a retrieve portal p ...), then we
  339.  * return the data to the user.  If the return value was palloc'ed,
  340.  * then it must also be freed.
  341.  */
  342. #ifndef NO_FASTPATH
  343. SendFunctionResult(fid, retval, fip->retbyval, fip->retlen);
  344. #else
  345. SendFunctionResult(fid, retval, fip->retbyval, 0);
  346. #endif  /* NO_FASTPATH */
  347. if (!fip->retbyval)
  348. pfree(retval);
  349. return 0;
  350. }