~ubuntu-branches/ubuntu/natty/postgresql-8.4/natty-updates

« back to all changes in this revision

Viewing changes to src/backend/tcop/fastpath.c

  • Committer: Bazaar Package Importer
  • Author(s): Martin Pitt
  • Date: 2009-03-20 12:00:13 UTC
  • Revision ID: james.westby@ubuntu.com-20090320120013-hogj7egc5mjncc5g
Tags: upstream-8.4~0cvs20090328
ImportĀ upstreamĀ versionĀ 8.4~0cvs20090328

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*-------------------------------------------------------------------------
 
2
 *
 
3
 * fastpath.c
 
4
 *        routines to handle function requests from the frontend
 
5
 *
 
6
 * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
 
7
 * Portions Copyright (c) 1994, Regents of the University of California
 
8
 *
 
9
 *
 
10
 * IDENTIFICATION
 
11
 *        $PostgreSQL$
 
12
 *
 
13
 * NOTES
 
14
 *        This cruft is the server side of PQfn.
 
15
 *
 
16
 *-------------------------------------------------------------------------
 
17
 */
 
18
#include "postgres.h"
 
19
 
 
20
#include <netinet/in.h>
 
21
#include <arpa/inet.h>
 
22
 
 
23
#include "access/xact.h"
 
24
#include "catalog/pg_proc.h"
 
25
#include "libpq/libpq.h"
 
26
#include "libpq/pqformat.h"
 
27
#include "mb/pg_wchar.h"
 
28
#include "miscadmin.h"
 
29
#include "tcop/fastpath.h"
 
30
#include "tcop/tcopprot.h"
 
31
#include "utils/acl.h"
 
32
#include "utils/lsyscache.h"
 
33
#include "utils/snapmgr.h"
 
34
#include "utils/syscache.h"
 
35
 
 
36
 
 
37
/*
 
38
 * Formerly, this code attempted to cache the function and type info
 
39
 * looked up by fetch_fp_info, but only for the duration of a single
 
40
 * transaction command (since in theory the info could change between
 
41
 * commands).  This was utterly useless, because postgres.c executes
 
42
 * each fastpath call as a separate transaction command, and so the
 
43
 * cached data could never actually have been reused.  If it had worked
 
44
 * as intended, it would have had problems anyway with dangling references
 
45
 * in the FmgrInfo struct.      So, forget about caching and just repeat the
 
46
 * syscache fetches on each usage.      They're not *that* expensive.
 
47
 */
 
48
struct fp_info
 
49
{
 
50
        Oid                     funcid;
 
51
        FmgrInfo        flinfo;                 /* function lookup info for funcid */
 
52
        Oid                     namespace;              /* other stuff from pg_proc */
 
53
        Oid                     rettype;
 
54
        Oid                     argtypes[FUNC_MAX_ARGS];
 
55
        char            fname[NAMEDATALEN];             /* function name for logging */
 
56
};
 
57
 
 
58
 
 
59
static int16 parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
 
60
                                          FunctionCallInfo fcinfo);
 
61
static int16 parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
 
62
                                                 FunctionCallInfo fcinfo);
 
63
 
 
64
 
 
65
/* ----------------
 
66
 *              GetOldFunctionMessage
 
67
 *
 
68
 * In pre-3.0 protocol, there is no length word on the message, so we have
 
69
 * to have code that understands the message layout to absorb the message
 
70
 * into a buffer.  We want to do this before we start execution, so that
 
71
 * we do not lose sync with the frontend if there's an error.
 
72
 *
 
73
 * The caller should already have initialized buf to empty.
 
74
 * ----------------
 
75
 */
 
76
static int
 
77
GetOldFunctionMessage(StringInfo buf)
 
78
{
 
79
        int32           ibuf;
 
80
        int                     nargs;
 
81
 
 
82
        /* Dummy string argument */
 
83
        if (pq_getstring(buf))
 
84
                return EOF;
 
85
        /* Function OID */
 
86
        if (pq_getbytes((char *) &ibuf, 4))
 
87
                return EOF;
 
88
        appendBinaryStringInfo(buf, (char *) &ibuf, 4);
 
89
        /* Number of arguments */
 
90
        if (pq_getbytes((char *) &ibuf, 4))
 
91
                return EOF;
 
92
        appendBinaryStringInfo(buf, (char *) &ibuf, 4);
 
93
        nargs = ntohl(ibuf);
 
94
        /* For each argument ... */
 
95
        while (nargs-- > 0)
 
96
        {
 
97
                int                     argsize;
 
98
 
 
99
                /* argsize */
 
100
                if (pq_getbytes((char *) &ibuf, 4))
 
101
                        return EOF;
 
102
                appendBinaryStringInfo(buf, (char *) &ibuf, 4);
 
103
                argsize = ntohl(ibuf);
 
104
                if (argsize < -1)
 
105
                {
 
106
                        /* FATAL here since no hope of regaining message sync */
 
107
                        ereport(FATAL,
 
108
                                        (errcode(ERRCODE_PROTOCOL_VIOLATION),
 
109
                                  errmsg("invalid argument size %d in function call message",
 
110
                                                 argsize)));
 
111
                }
 
112
                /* and arg contents */
 
113
                if (argsize > 0)
 
114
                {
 
115
                        /* Allocate space for arg */
 
116
                        enlargeStringInfo(buf, argsize);
 
117
                        /* And grab it */
 
118
                        if (pq_getbytes(buf->data + buf->len, argsize))
 
119
                                return EOF;
 
120
                        buf->len += argsize;
 
121
                        /* Place a trailing null per StringInfo convention */
 
122
                        buf->data[buf->len] = '\0';
 
123
                }
 
124
        }
 
125
        return 0;
 
126
}
 
127
 
 
128
/* ----------------
 
129
 *              SendFunctionResult
 
130
 *
 
131
 * Note: although this routine doesn't check, the format had better be 1
 
132
 * (binary) when talking to a pre-3.0 client.
 
133
 * ----------------
 
134
 */
 
135
static void
 
136
SendFunctionResult(Datum retval, bool isnull, Oid rettype, int16 format)
 
137
{
 
138
        bool            newstyle = (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3);
 
139
        StringInfoData buf;
 
140
 
 
141
        pq_beginmessage(&buf, 'V');
 
142
 
 
143
        if (isnull)
 
144
        {
 
145
                if (newstyle)
 
146
                        pq_sendint(&buf, -1, 4);
 
147
        }
 
148
        else
 
149
        {
 
150
                if (!newstyle)
 
151
                        pq_sendbyte(&buf, 'G');
 
152
 
 
153
                if (format == 0)
 
154
                {
 
155
                        Oid                     typoutput;
 
156
                        bool            typisvarlena;
 
157
                        char       *outputstr;
 
158
 
 
159
                        getTypeOutputInfo(rettype, &typoutput, &typisvarlena);
 
160
                        outputstr = OidOutputFunctionCall(typoutput, retval);
 
161
                        pq_sendcountedtext(&buf, outputstr, strlen(outputstr), false);
 
162
                        pfree(outputstr);
 
163
                }
 
164
                else if (format == 1)
 
165
                {
 
166
                        Oid                     typsend;
 
167
                        bool            typisvarlena;
 
168
                        bytea      *outputbytes;
 
169
 
 
170
                        getTypeBinaryOutputInfo(rettype, &typsend, &typisvarlena);
 
171
                        outputbytes = OidSendFunctionCall(typsend, retval);
 
172
                        pq_sendint(&buf, VARSIZE(outputbytes) - VARHDRSZ, 4);
 
173
                        pq_sendbytes(&buf, VARDATA(outputbytes),
 
174
                                                 VARSIZE(outputbytes) - VARHDRSZ);
 
175
                        pfree(outputbytes);
 
176
                }
 
177
                else
 
178
                        ereport(ERROR,
 
179
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
180
                                         errmsg("unsupported format code: %d", format)));
 
181
        }
 
182
 
 
183
        if (!newstyle)
 
184
                pq_sendbyte(&buf, '0');
 
185
 
 
186
        pq_endmessage(&buf);
 
187
}
 
188
 
 
189
/*
 
190
 * fetch_fp_info
 
191
 *
 
192
 * Performs catalog lookups to load a struct fp_info 'fip' for the
 
193
 * function 'func_id'.
 
194
 */
 
195
static void
 
196
fetch_fp_info(Oid func_id, struct fp_info * fip)
 
197
{
 
198
        HeapTuple       func_htp;
 
199
        Form_pg_proc pp;
 
200
 
 
201
        Assert(OidIsValid(func_id));
 
202
        Assert(fip != NULL);
 
203
 
 
204
        /*
 
205
         * Since the validity of this structure is determined by whether the
 
206
         * funcid is OK, we clear the funcid here.      It must not be set to the
 
207
         * correct value until we are about to return with a good struct fp_info,
 
208
         * since we can be interrupted (i.e., with an ereport(ERROR, ...)) at any
 
209
         * time.  [No longer really an issue since we don't save the struct
 
210
         * fp_info across transactions anymore, but keep it anyway.]
 
211
         */
 
212
        MemSet(fip, 0, sizeof(struct fp_info));
 
213
        fip->funcid = InvalidOid;
 
214
 
 
215
        fmgr_info(func_id, &fip->flinfo);
 
216
 
 
217
        func_htp = SearchSysCache(PROCOID,
 
218
                                                          ObjectIdGetDatum(func_id),
 
219
                                                          0, 0, 0);
 
220
        if (!HeapTupleIsValid(func_htp))
 
221
                ereport(ERROR,
 
222
                                (errcode(ERRCODE_UNDEFINED_FUNCTION),
 
223
                                 errmsg("function with OID %u does not exist", func_id)));
 
224
        pp = (Form_pg_proc) GETSTRUCT(func_htp);
 
225
 
 
226
        /* watch out for catalog entries with more than FUNC_MAX_ARGS args */
 
227
        if (pp->pronargs > FUNC_MAX_ARGS)
 
228
                elog(ERROR, "function %s has more than %d arguments",
 
229
                         NameStr(pp->proname), FUNC_MAX_ARGS);
 
230
 
 
231
        fip->namespace = pp->pronamespace;
 
232
        fip->rettype = pp->prorettype;
 
233
        memcpy(fip->argtypes, pp->proargtypes.values, pp->pronargs * sizeof(Oid));
 
234
        strlcpy(fip->fname, NameStr(pp->proname), NAMEDATALEN);
 
235
 
 
236
        ReleaseSysCache(func_htp);
 
237
 
 
238
        /*
 
239
         * This must be last!
 
240
         */
 
241
        fip->funcid = func_id;
 
242
}
 
243
 
 
244
 
 
245
/*
 
246
 * HandleFunctionRequest
 
247
 *
 
248
 * Server side of PQfn (fastpath function calls from the frontend).
 
249
 * This corresponds to the libpq protocol symbol "F".
 
250
 *
 
251
 * INPUT:
 
252
 *              In protocol version 3, postgres.c has already read the message body
 
253
 *              and will pass it in msgBuf.
 
254
 *              In old protocol, the passed msgBuf is empty and we must read the
 
255
 *              message here.
 
256
 *
 
257
 * RETURNS:
 
258
 *              0 if successful completion, EOF if frontend connection lost.
 
259
 *
 
260
 * Note: All ordinary errors result in ereport(ERROR,...).      However,
 
261
 * if we lose the frontend connection there is no one to ereport to,
 
262
 * and no use in proceeding...
 
263
 *
 
264
 * Note: palloc()s done here and in the called function do not need to be
 
265
 * cleaned up explicitly.  We are called from PostgresMain() in the
 
266
 * MessageContext memory context, which will be automatically reset when
 
267
 * control returns to PostgresMain.
 
268
 */
 
269
int
 
270
HandleFunctionRequest(StringInfo msgBuf)
 
271
{
 
272
        Oid                     fid;
 
273
        AclResult       aclresult;
 
274
        FunctionCallInfoData fcinfo;
 
275
        int16           rformat;
 
276
        Datum           retval;
 
277
        struct fp_info my_fp;
 
278
        struct fp_info *fip;
 
279
        bool            callit;
 
280
        bool            was_logged = false;
 
281
        char            msec_str[32];
 
282
 
 
283
        /*
 
284
         * Read message contents if not already done.
 
285
         */
 
286
        if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
 
287
        {
 
288
                if (GetOldFunctionMessage(msgBuf))
 
289
                {
 
290
                        ereport(COMMERROR,
 
291
                                        (errcode(ERRCODE_PROTOCOL_VIOLATION),
 
292
                                         errmsg("unexpected EOF on client connection")));
 
293
                        return EOF;
 
294
                }
 
295
        }
 
296
 
 
297
        /*
 
298
         * Now that we've eaten the input message, check to see if we actually
 
299
         * want to do the function call or not.  It's now safe to ereport(); we
 
300
         * won't lose sync with the frontend.
 
301
         */
 
302
        if (IsAbortedTransactionBlockState())
 
303
                ereport(ERROR,
 
304
                                (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
 
305
                                 errmsg("current transaction is aborted, "
 
306
                                                "commands ignored until end of transaction block")));
 
307
 
 
308
        /*
 
309
         * Now that we know we are in a valid transaction, set snapshot in case
 
310
         * needed by function itself or one of the datatype I/O routines.
 
311
         */
 
312
        PushActiveSnapshot(GetTransactionSnapshot());
 
313
 
 
314
        /*
 
315
         * Begin parsing the buffer contents.
 
316
         */
 
317
        if (PG_PROTOCOL_MAJOR(FrontendProtocol) < 3)
 
318
                (void) pq_getmsgstring(msgBuf); /* dummy string */
 
319
 
 
320
        fid = (Oid) pq_getmsgint(msgBuf, 4);            /* function oid */
 
321
 
 
322
        /*
 
323
         * There used to be a lame attempt at caching lookup info here. Now we
 
324
         * just do the lookups on every call.
 
325
         */
 
326
        fip = &my_fp;
 
327
        fetch_fp_info(fid, fip);
 
328
 
 
329
        /* Log as soon as we have the function OID and name */
 
330
        if (log_statement == LOGSTMT_ALL)
 
331
        {
 
332
                ereport(LOG,
 
333
                                (errmsg("fastpath function call: \"%s\" (OID %u)",
 
334
                                                fip->fname, fid)));
 
335
                was_logged = true;
 
336
        }
 
337
 
 
338
        /*
 
339
         * Check permission to access and call function.  Since we didn't go
 
340
         * through a normal name lookup, we need to check schema usage too.
 
341
         */
 
342
        aclresult = pg_namespace_aclcheck(fip->namespace, GetUserId(), ACL_USAGE);
 
343
        if (aclresult != ACLCHECK_OK)
 
344
                aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
 
345
                                           get_namespace_name(fip->namespace));
 
346
 
 
347
        aclresult = pg_proc_aclcheck(fid, GetUserId(), ACL_EXECUTE);
 
348
        if (aclresult != ACLCHECK_OK)
 
349
                aclcheck_error(aclresult, ACL_KIND_PROC,
 
350
                                           get_func_name(fid));
 
351
 
 
352
        /*
 
353
         * Prepare function call info block and insert arguments.
 
354
         */
 
355
        InitFunctionCallInfoData(fcinfo, &fip->flinfo, 0, NULL, NULL);
 
356
 
 
357
        if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 3)
 
358
                rformat = parse_fcall_arguments(msgBuf, fip, &fcinfo);
 
359
        else
 
360
                rformat = parse_fcall_arguments_20(msgBuf, fip, &fcinfo);
 
361
 
 
362
        /* Verify we reached the end of the message where expected. */
 
363
        pq_getmsgend(msgBuf);
 
364
 
 
365
        /*
 
366
         * If func is strict, must not call it for null args.
 
367
         */
 
368
        callit = true;
 
369
        if (fip->flinfo.fn_strict)
 
370
        {
 
371
                int                     i;
 
372
 
 
373
                for (i = 0; i < fcinfo.nargs; i++)
 
374
                {
 
375
                        if (fcinfo.argnull[i])
 
376
                        {
 
377
                                callit = false;
 
378
                                break;
 
379
                        }
 
380
                }
 
381
        }
 
382
 
 
383
        if (callit)
 
384
        {
 
385
                /* Okay, do it ... */
 
386
                retval = FunctionCallInvoke(&fcinfo);
 
387
        }
 
388
        else
 
389
        {
 
390
                fcinfo.isnull = true;
 
391
                retval = (Datum) 0;
 
392
        }
 
393
 
 
394
        /* ensure we do at least one CHECK_FOR_INTERRUPTS per function call */
 
395
        CHECK_FOR_INTERRUPTS();
 
396
 
 
397
        SendFunctionResult(retval, fcinfo.isnull, fip->rettype, rformat);
 
398
 
 
399
        /* We no longer need the snapshot */
 
400
        PopActiveSnapshot();
 
401
 
 
402
        /*
 
403
         * Emit duration logging if appropriate.
 
404
         */
 
405
        switch (check_log_duration(msec_str, was_logged))
 
406
        {
 
407
                case 1:
 
408
                        ereport(LOG,
 
409
                                        (errmsg("duration: %s ms", msec_str)));
 
410
                        break;
 
411
                case 2:
 
412
                        ereport(LOG,
 
413
                                        (errmsg("duration: %s ms  fastpath function call: \"%s\" (OID %u)",
 
414
                                                        msec_str, fip->fname, fid)));
 
415
                        break;
 
416
        }
 
417
 
 
418
        return 0;
 
419
}
 
420
 
 
421
/*
 
422
 * Parse function arguments in a 3.0 protocol message
 
423
 *
 
424
 * Argument values are loaded into *fcinfo, and the desired result format
 
425
 * is returned.
 
426
 */
 
427
static int16
 
428
parse_fcall_arguments(StringInfo msgBuf, struct fp_info * fip,
 
429
                                          FunctionCallInfo fcinfo)
 
430
{
 
431
        int                     nargs;
 
432
        int                     i;
 
433
        int                     numAFormats;
 
434
        int16      *aformats = NULL;
 
435
        StringInfoData abuf;
 
436
 
 
437
        /* Get the argument format codes */
 
438
        numAFormats = pq_getmsgint(msgBuf, 2);
 
439
        if (numAFormats > 0)
 
440
        {
 
441
                aformats = (int16 *) palloc(numAFormats * sizeof(int16));
 
442
                for (i = 0; i < numAFormats; i++)
 
443
                        aformats[i] = pq_getmsgint(msgBuf, 2);
 
444
        }
 
445
 
 
446
        nargs = pq_getmsgint(msgBuf, 2);        /* # of arguments */
 
447
 
 
448
        if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
 
449
                ereport(ERROR,
 
450
                                (errcode(ERRCODE_PROTOCOL_VIOLATION),
 
451
                                 errmsg("function call message contains %d arguments but function requires %d",
 
452
                                                nargs, fip->flinfo.fn_nargs)));
 
453
 
 
454
        fcinfo->nargs = nargs;
 
455
 
 
456
        if (numAFormats > 1 && numAFormats != nargs)
 
457
                ereport(ERROR,
 
458
                                (errcode(ERRCODE_PROTOCOL_VIOLATION),
 
459
                                 errmsg("function call message contains %d argument formats but %d arguments",
 
460
                                                numAFormats, nargs)));
 
461
 
 
462
        initStringInfo(&abuf);
 
463
 
 
464
        /*
 
465
         * Copy supplied arguments into arg vector.
 
466
         */
 
467
        for (i = 0; i < nargs; ++i)
 
468
        {
 
469
                int                     argsize;
 
470
                int16           aformat;
 
471
 
 
472
                argsize = pq_getmsgint(msgBuf, 4);
 
473
                if (argsize == -1)
 
474
                {
 
475
                        fcinfo->argnull[i] = true;
 
476
                }
 
477
                else
 
478
                {
 
479
                        fcinfo->argnull[i] = false;
 
480
                        if (argsize < 0)
 
481
                                ereport(ERROR,
 
482
                                                (errcode(ERRCODE_PROTOCOL_VIOLATION),
 
483
                                  errmsg("invalid argument size %d in function call message",
 
484
                                                 argsize)));
 
485
 
 
486
                        /* Reset abuf to empty, and insert raw data into it */
 
487
                        resetStringInfo(&abuf);
 
488
                        appendBinaryStringInfo(&abuf,
 
489
                                                                   pq_getmsgbytes(msgBuf, argsize),
 
490
                                                                   argsize);
 
491
                }
 
492
 
 
493
                if (numAFormats > 1)
 
494
                        aformat = aformats[i];
 
495
                else if (numAFormats > 0)
 
496
                        aformat = aformats[0];
 
497
                else
 
498
                        aformat = 0;            /* default = text */
 
499
 
 
500
                if (aformat == 0)
 
501
                {
 
502
                        Oid                     typinput;
 
503
                        Oid                     typioparam;
 
504
                        char       *pstring;
 
505
 
 
506
                        getTypeInputInfo(fip->argtypes[i], &typinput, &typioparam);
 
507
 
 
508
                        /*
 
509
                         * Since stringinfo.c keeps a trailing null in place even for
 
510
                         * binary data, the contents of abuf are a valid C string.      We
 
511
                         * have to do encoding conversion before calling the typinput
 
512
                         * routine, though.
 
513
                         */
 
514
                        if (argsize == -1)
 
515
                                pstring = NULL;
 
516
                        else
 
517
                                pstring = pg_client_to_server(abuf.data, argsize);
 
518
 
 
519
                        fcinfo->arg[i] = OidInputFunctionCall(typinput, pstring,
 
520
                                                                                                  typioparam, -1);
 
521
                        /* Free result of encoding conversion, if any */
 
522
                        if (pstring && pstring != abuf.data)
 
523
                                pfree(pstring);
 
524
                }
 
525
                else if (aformat == 1)
 
526
                {
 
527
                        Oid                     typreceive;
 
528
                        Oid                     typioparam;
 
529
                        StringInfo      bufptr;
 
530
 
 
531
                        /* Call the argument type's binary input converter */
 
532
                        getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
 
533
 
 
534
                        if (argsize == -1)
 
535
                                bufptr = NULL;
 
536
                        else
 
537
                                bufptr = &abuf;
 
538
 
 
539
                        fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, bufptr,
 
540
                                                                                                        typioparam, -1);
 
541
 
 
542
                        /* Trouble if it didn't eat the whole buffer */
 
543
                        if (argsize != -1 && abuf.cursor != abuf.len)
 
544
                                ereport(ERROR,
 
545
                                                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 
546
                                errmsg("incorrect binary data format in function argument %d",
 
547
                                           i + 1)));
 
548
                }
 
549
                else
 
550
                        ereport(ERROR,
 
551
                                        (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
 
552
                                         errmsg("unsupported format code: %d", aformat)));
 
553
        }
 
554
 
 
555
        /* Return result format code */
 
556
        return (int16) pq_getmsgint(msgBuf, 2);
 
557
}
 
558
 
 
559
/*
 
560
 * Parse function arguments in a 2.0 protocol message
 
561
 *
 
562
 * Argument values are loaded into *fcinfo, and the desired result format
 
563
 * is returned.
 
564
 */
 
565
static int16
 
566
parse_fcall_arguments_20(StringInfo msgBuf, struct fp_info * fip,
 
567
                                                 FunctionCallInfo fcinfo)
 
568
{
 
569
        int                     nargs;
 
570
        int                     i;
 
571
        StringInfoData abuf;
 
572
 
 
573
        nargs = pq_getmsgint(msgBuf, 4);        /* # of arguments */
 
574
 
 
575
        if (fip->flinfo.fn_nargs != nargs || nargs > FUNC_MAX_ARGS)
 
576
                ereport(ERROR,
 
577
                                (errcode(ERRCODE_PROTOCOL_VIOLATION),
 
578
                                 errmsg("function call message contains %d arguments but function requires %d",
 
579
                                                nargs, fip->flinfo.fn_nargs)));
 
580
 
 
581
        fcinfo->nargs = nargs;
 
582
 
 
583
        initStringInfo(&abuf);
 
584
 
 
585
        /*
 
586
         * Copy supplied arguments into arg vector.  In protocol 2.0 these are
 
587
         * always assumed to be supplied in binary format.
 
588
         *
 
589
         * Note: although the original protocol 2.0 code did not have any way for
 
590
         * the frontend to specify a NULL argument, we now choose to interpret
 
591
         * length == -1 as meaning a NULL.
 
592
         */
 
593
        for (i = 0; i < nargs; ++i)
 
594
        {
 
595
                int                     argsize;
 
596
                Oid                     typreceive;
 
597
                Oid                     typioparam;
 
598
 
 
599
                getTypeBinaryInputInfo(fip->argtypes[i], &typreceive, &typioparam);
 
600
 
 
601
                argsize = pq_getmsgint(msgBuf, 4);
 
602
                if (argsize == -1)
 
603
                {
 
604
                        fcinfo->argnull[i] = true;
 
605
                        fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, NULL,
 
606
                                                                                                        typioparam, -1);
 
607
                        continue;
 
608
                }
 
609
                fcinfo->argnull[i] = false;
 
610
                if (argsize < 0)
 
611
                        ereport(ERROR,
 
612
                                        (errcode(ERRCODE_PROTOCOL_VIOLATION),
 
613
                                  errmsg("invalid argument size %d in function call message",
 
614
                                                 argsize)));
 
615
 
 
616
                /* Reset abuf to empty, and insert raw data into it */
 
617
                resetStringInfo(&abuf);
 
618
                appendBinaryStringInfo(&abuf,
 
619
                                                           pq_getmsgbytes(msgBuf, argsize),
 
620
                                                           argsize);
 
621
 
 
622
                fcinfo->arg[i] = OidReceiveFunctionCall(typreceive, &abuf,
 
623
                                                                                                typioparam, -1);
 
624
 
 
625
                /* Trouble if it didn't eat the whole buffer */
 
626
                if (abuf.cursor != abuf.len)
 
627
                        ereport(ERROR,
 
628
                                        (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
 
629
                           errmsg("incorrect binary data format in function argument %d",
 
630
                                          i + 1)));
 
631
        }
 
632
 
 
633
        /* Desired result format is always binary in protocol 2.0 */
 
634
        return 1;
 
635
}