]> granicus.if.org Git - postgresql/blob - src/backend/executor/spi.c
Fix oversight in initial implementation of PORTAL_ONE_RETURNING mode: we
[postgresql] / src / backend / executor / spi.c
1 /*-------------------------------------------------------------------------
2  *
3  * spi.c
4  *                              Server Programming Interface
5  *
6  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.157 2006/08/14 22:57:15 tgl Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/printtup.h"
18 #include "catalog/heap.h"
19 #include "commands/trigger.h"
20 #include "executor/spi_priv.h"
21 #include "utils/lsyscache.h"
22 #include "utils/memutils.h"
23 #include "utils/typcache.h"
24
25
26 uint32          SPI_processed = 0;
27 Oid                     SPI_lastoid = InvalidOid;
28 SPITupleTable *SPI_tuptable = NULL;
29 int                     SPI_result;
30
31 static _SPI_connection *_SPI_stack = NULL;
32 static _SPI_connection *_SPI_current = NULL;
33 static int      _SPI_stack_depth = 0;           /* allocated size of _SPI_stack */
34 static int      _SPI_connected = -1;
35 static int      _SPI_curid = -1;
36
37 static void _SPI_prepare_plan(const char *src, _SPI_plan *plan);
38
39 static int _SPI_execute_plan(_SPI_plan *plan,
40                                   Datum *Values, const char *Nulls,
41                                   Snapshot snapshot, Snapshot crosscheck_snapshot,
42                                   bool read_only, long tcount);
43
44 static int      _SPI_pquery(QueryDesc *queryDesc, long tcount);
45
46 static void _SPI_error_callback(void *arg);
47
48 static void _SPI_cursor_operation(Portal portal, bool forward, long count,
49                                           DestReceiver *dest);
50
51 static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location);
52
53 static int      _SPI_begin_call(bool execmem);
54 static int      _SPI_end_call(bool procmem);
55 static MemoryContext _SPI_execmem(void);
56 static MemoryContext _SPI_procmem(void);
57 static bool _SPI_checktuples(void);
58
59
60 /* =================== interface functions =================== */
61
62 int
63 SPI_connect(void)
64 {
65         int                     newdepth;
66
67         /*
68          * When procedure called by Executor _SPI_curid expected to be equal to
69          * _SPI_connected
70          */
71         if (_SPI_curid != _SPI_connected)
72                 return SPI_ERROR_CONNECT;
73
74         if (_SPI_stack == NULL)
75         {
76                 if (_SPI_connected != -1 || _SPI_stack_depth != 0)
77                         elog(ERROR, "SPI stack corrupted");
78                 newdepth = 16;
79                 _SPI_stack = (_SPI_connection *)
80                         MemoryContextAlloc(TopTransactionContext,
81                                                            newdepth * sizeof(_SPI_connection));
82                 _SPI_stack_depth = newdepth;
83         }
84         else
85         {
86                 if (_SPI_stack_depth <= 0 || _SPI_stack_depth <= _SPI_connected)
87                         elog(ERROR, "SPI stack corrupted");
88                 if (_SPI_stack_depth == _SPI_connected + 1)
89                 {
90                         newdepth = _SPI_stack_depth * 2;
91                         _SPI_stack = (_SPI_connection *)
92                                 repalloc(_SPI_stack,
93                                                  newdepth * sizeof(_SPI_connection));
94                         _SPI_stack_depth = newdepth;
95                 }
96         }
97
98         /*
99          * We're entering procedure where _SPI_curid == _SPI_connected - 1
100          */
101         _SPI_connected++;
102         Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth);
103
104         _SPI_current = &(_SPI_stack[_SPI_connected]);
105         _SPI_current->processed = 0;
106         _SPI_current->lastoid = InvalidOid;
107         _SPI_current->tuptable = NULL;
108         _SPI_current->procCxt = NULL;           /* in case we fail to create 'em */
109         _SPI_current->execCxt = NULL;
110         _SPI_current->connectSubid = GetCurrentSubTransactionId();
111
112         /*
113          * Create memory contexts for this procedure
114          *
115          * XXX it would be better to use PortalContext as the parent context, but
116          * we may not be inside a portal (consider deferred-trigger execution).
117          * Perhaps CurTransactionContext would do?      For now it doesn't matter
118          * because we clean up explicitly in AtEOSubXact_SPI().
119          */
120         _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
121                                                                                                   "SPI Proc",
122                                                                                                   ALLOCSET_DEFAULT_MINSIZE,
123                                                                                                   ALLOCSET_DEFAULT_INITSIZE,
124                                                                                                   ALLOCSET_DEFAULT_MAXSIZE);
125         _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
126                                                                                                   "SPI Exec",
127                                                                                                   ALLOCSET_DEFAULT_MINSIZE,
128                                                                                                   ALLOCSET_DEFAULT_INITSIZE,
129                                                                                                   ALLOCSET_DEFAULT_MAXSIZE);
130         /* ... and switch to procedure's context */
131         _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
132
133         return SPI_OK_CONNECT;
134 }
135
136 int
137 SPI_finish(void)
138 {
139         int                     res;
140
141         res = _SPI_begin_call(false);           /* live in procedure memory */
142         if (res < 0)
143                 return res;
144
145         /* Restore memory context as it was before procedure call */
146         MemoryContextSwitchTo(_SPI_current->savedcxt);
147
148         /* Release memory used in procedure call */
149         MemoryContextDelete(_SPI_current->execCxt);
150         _SPI_current->execCxt = NULL;
151         MemoryContextDelete(_SPI_current->procCxt);
152         _SPI_current->procCxt = NULL;
153
154         /*
155          * Reset result variables, especially SPI_tuptable which is probably
156          * pointing at a just-deleted tuptable
157          */
158         SPI_processed = 0;
159         SPI_lastoid = InvalidOid;
160         SPI_tuptable = NULL;
161
162         /*
163          * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are closing
164          * connection to SPI and returning to upper Executor and so _SPI_connected
165          * must be equal to _SPI_curid.
166          */
167         _SPI_connected--;
168         _SPI_curid--;
169         if (_SPI_connected == -1)
170                 _SPI_current = NULL;
171         else
172                 _SPI_current = &(_SPI_stack[_SPI_connected]);
173
174         return SPI_OK_FINISH;
175 }
176
177 /*
178  * Clean up SPI state at transaction commit or abort.
179  */
180 void
181 AtEOXact_SPI(bool isCommit)
182 {
183         /*
184          * Note that memory contexts belonging to SPI stack entries will be freed
185          * automatically, so we can ignore them here.  We just need to restore our
186          * static variables to initial state.
187          */
188         if (isCommit && _SPI_connected != -1)
189                 ereport(WARNING,
190                                 (errcode(ERRCODE_WARNING),
191                                  errmsg("transaction left non-empty SPI stack"),
192                                  errhint("Check for missing \"SPI_finish\" calls.")));
193
194         _SPI_current = _SPI_stack = NULL;
195         _SPI_stack_depth = 0;
196         _SPI_connected = _SPI_curid = -1;
197         SPI_processed = 0;
198         SPI_lastoid = InvalidOid;
199         SPI_tuptable = NULL;
200 }
201
202 /*
203  * Clean up SPI state at subtransaction commit or abort.
204  *
205  * During commit, there shouldn't be any unclosed entries remaining from
206  * the current subtransaction; we emit a warning if any are found.
207  */
208 void
209 AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
210 {
211         bool            found = false;
212
213         while (_SPI_connected >= 0)
214         {
215                 _SPI_connection *connection = &(_SPI_stack[_SPI_connected]);
216
217                 if (connection->connectSubid != mySubid)
218                         break;                          /* couldn't be any underneath it either */
219
220                 found = true;
221
222                 /*
223                  * Release procedure memory explicitly (see note in SPI_connect)
224                  */
225                 if (connection->execCxt)
226                 {
227                         MemoryContextDelete(connection->execCxt);
228                         connection->execCxt = NULL;
229                 }
230                 if (connection->procCxt)
231                 {
232                         MemoryContextDelete(connection->procCxt);
233                         connection->procCxt = NULL;
234                 }
235
236                 /*
237                  * Pop the stack entry and reset global variables.      Unlike
238                  * SPI_finish(), we don't risk switching to memory contexts that might
239                  * be already gone.
240                  */
241                 _SPI_connected--;
242                 _SPI_curid = _SPI_connected;
243                 if (_SPI_connected == -1)
244                         _SPI_current = NULL;
245                 else
246                         _SPI_current = &(_SPI_stack[_SPI_connected]);
247                 SPI_processed = 0;
248                 SPI_lastoid = InvalidOid;
249                 SPI_tuptable = NULL;
250         }
251
252         if (found && isCommit)
253                 ereport(WARNING,
254                                 (errcode(ERRCODE_WARNING),
255                                  errmsg("subtransaction left non-empty SPI stack"),
256                                  errhint("Check for missing \"SPI_finish\" calls.")));
257 }
258
259
260 /* Pushes SPI stack to allow recursive SPI calls */
261 void
262 SPI_push(void)
263 {
264         _SPI_curid++;
265 }
266
267 /* Pops SPI stack to allow recursive SPI calls */
268 void
269 SPI_pop(void)
270 {
271         _SPI_curid--;
272 }
273
274 /* Restore state of SPI stack after aborting a subtransaction */
275 void
276 SPI_restore_connection(void)
277 {
278         Assert(_SPI_connected >= 0);
279         _SPI_curid = _SPI_connected - 1;
280 }
281
282 /* Parse, plan, and execute a query string */
283 int
284 SPI_execute(const char *src, bool read_only, long tcount)
285 {
286         _SPI_plan       plan;
287         int                     res;
288
289         if (src == NULL || tcount < 0)
290                 return SPI_ERROR_ARGUMENT;
291
292         res = _SPI_begin_call(true);
293         if (res < 0)
294                 return res;
295
296         plan.plancxt = NULL;            /* doesn't have own context */
297         plan.query = src;
298         plan.nargs = 0;
299         plan.argtypes = NULL;
300
301         _SPI_prepare_plan(src, &plan);
302
303         res = _SPI_execute_plan(&plan, NULL, NULL,
304                                                         InvalidSnapshot, InvalidSnapshot,
305                                                         read_only, tcount);
306
307         _SPI_end_call(true);
308         return res;
309 }
310
311 /* Obsolete version of SPI_execute */
312 int
313 SPI_exec(const char *src, long tcount)
314 {
315         return SPI_execute(src, false, tcount);
316 }
317
318 /* Execute a previously prepared plan */
319 int
320 SPI_execute_plan(void *plan, Datum *Values, const char *Nulls,
321                                  bool read_only, long tcount)
322 {
323         int                     res;
324
325         if (plan == NULL || tcount < 0)
326                 return SPI_ERROR_ARGUMENT;
327
328         if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
329                 return SPI_ERROR_PARAM;
330
331         res = _SPI_begin_call(true);
332         if (res < 0)
333                 return res;
334
335         res = _SPI_execute_plan((_SPI_plan *) plan,
336                                                         Values, Nulls,
337                                                         InvalidSnapshot, InvalidSnapshot,
338                                                         read_only, tcount);
339
340         _SPI_end_call(true);
341         return res;
342 }
343
344 /* Obsolete version of SPI_execute_plan */
345 int
346 SPI_execp(void *plan, Datum *Values, const char *Nulls, long tcount)
347 {
348         return SPI_execute_plan(plan, Values, Nulls, false, tcount);
349 }
350
351 /*
352  * SPI_execute_snapshot -- identical to SPI_execute_plan, except that we allow
353  * the caller to specify exactly which snapshots to use.  This is currently
354  * not documented in spi.sgml because it is only intended for use by RI
355  * triggers.
356  *
357  * Passing snapshot == InvalidSnapshot will select the normal behavior of
358  * fetching a new snapshot for each query.
359  */
360 int
361 SPI_execute_snapshot(void *plan,
362                                          Datum *Values, const char *Nulls,
363                                          Snapshot snapshot, Snapshot crosscheck_snapshot,
364                                          bool read_only, long tcount)
365 {
366         int                     res;
367
368         if (plan == NULL || tcount < 0)
369                 return SPI_ERROR_ARGUMENT;
370
371         if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
372                 return SPI_ERROR_PARAM;
373
374         res = _SPI_begin_call(true);
375         if (res < 0)
376                 return res;
377
378         res = _SPI_execute_plan((_SPI_plan *) plan,
379                                                         Values, Nulls,
380                                                         snapshot, crosscheck_snapshot,
381                                                         read_only, tcount);
382
383         _SPI_end_call(true);
384         return res;
385 }
386
387 void *
388 SPI_prepare(const char *src, int nargs, Oid *argtypes)
389 {
390         _SPI_plan       plan;
391         _SPI_plan  *result;
392
393         if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
394         {
395                 SPI_result = SPI_ERROR_ARGUMENT;
396                 return NULL;
397         }
398
399         SPI_result = _SPI_begin_call(true);
400         if (SPI_result < 0)
401                 return NULL;
402
403         plan.plancxt = NULL;            /* doesn't have own context */
404         plan.query = src;
405         plan.nargs = nargs;
406         plan.argtypes = argtypes;
407
408         _SPI_prepare_plan(src, &plan);
409
410         /* copy plan to procedure context */
411         result = _SPI_copy_plan(&plan, _SPI_CPLAN_PROCXT);
412
413         _SPI_end_call(true);
414
415         return (void *) result;
416 }
417
418 void *
419 SPI_saveplan(void *plan)
420 {
421         _SPI_plan  *newplan;
422
423         if (plan == NULL)
424         {
425                 SPI_result = SPI_ERROR_ARGUMENT;
426                 return NULL;
427         }
428
429         SPI_result = _SPI_begin_call(false);            /* don't change context */
430         if (SPI_result < 0)
431                 return NULL;
432
433         newplan = _SPI_copy_plan((_SPI_plan *) plan, _SPI_CPLAN_TOPCXT);
434
435         _SPI_curid--;
436         SPI_result = 0;
437
438         return (void *) newplan;
439 }
440
441 int
442 SPI_freeplan(void *plan)
443 {
444         _SPI_plan  *spiplan = (_SPI_plan *) plan;
445
446         if (plan == NULL)
447                 return SPI_ERROR_ARGUMENT;
448
449         MemoryContextDelete(spiplan->plancxt);
450         return 0;
451 }
452
453 HeapTuple
454 SPI_copytuple(HeapTuple tuple)
455 {
456         MemoryContext oldcxt = NULL;
457         HeapTuple       ctuple;
458
459         if (tuple == NULL)
460         {
461                 SPI_result = SPI_ERROR_ARGUMENT;
462                 return NULL;
463         }
464
465         if (_SPI_curid + 1 == _SPI_connected)           /* connected */
466         {
467                 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
468                         elog(ERROR, "SPI stack corrupted");
469                 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
470         }
471
472         ctuple = heap_copytuple(tuple);
473
474         if (oldcxt)
475                 MemoryContextSwitchTo(oldcxt);
476
477         return ctuple;
478 }
479
480 HeapTupleHeader
481 SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
482 {
483         MemoryContext oldcxt = NULL;
484         HeapTupleHeader dtup;
485
486         if (tuple == NULL || tupdesc == NULL)
487         {
488                 SPI_result = SPI_ERROR_ARGUMENT;
489                 return NULL;
490         }
491
492         /* For RECORD results, make sure a typmod has been assigned */
493         if (tupdesc->tdtypeid == RECORDOID &&
494                 tupdesc->tdtypmod < 0)
495                 assign_record_type_typmod(tupdesc);
496
497         if (_SPI_curid + 1 == _SPI_connected)           /* connected */
498         {
499                 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
500                         elog(ERROR, "SPI stack corrupted");
501                 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
502         }
503
504         dtup = (HeapTupleHeader) palloc(tuple->t_len);
505         memcpy((char *) dtup, (char *) tuple->t_data, tuple->t_len);
506
507         HeapTupleHeaderSetDatumLength(dtup, tuple->t_len);
508         HeapTupleHeaderSetTypeId(dtup, tupdesc->tdtypeid);
509         HeapTupleHeaderSetTypMod(dtup, tupdesc->tdtypmod);
510
511         if (oldcxt)
512                 MemoryContextSwitchTo(oldcxt);
513
514         return dtup;
515 }
516
517 HeapTuple
518 SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
519                                 Datum *Values, const char *Nulls)
520 {
521         MemoryContext oldcxt = NULL;
522         HeapTuple       mtuple;
523         int                     numberOfAttributes;
524         Datum      *v;
525         char       *n;
526         int                     i;
527
528         if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
529         {
530                 SPI_result = SPI_ERROR_ARGUMENT;
531                 return NULL;
532         }
533
534         if (_SPI_curid + 1 == _SPI_connected)           /* connected */
535         {
536                 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
537                         elog(ERROR, "SPI stack corrupted");
538                 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
539         }
540         SPI_result = 0;
541         numberOfAttributes = rel->rd_att->natts;
542         v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
543         n = (char *) palloc(numberOfAttributes * sizeof(char));
544
545         /* fetch old values and nulls */
546         heap_deformtuple(tuple, rel->rd_att, v, n);
547
548         /* replace values and nulls */
549         for (i = 0; i < natts; i++)
550         {
551                 if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
552                         break;
553                 v[attnum[i] - 1] = Values[i];
554                 n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? 'n' : ' ';
555         }
556
557         if (i == natts)                         /* no errors in *attnum */
558         {
559                 mtuple = heap_formtuple(rel->rd_att, v, n);
560
561                 /*
562                  * copy the identification info of the old tuple: t_ctid, t_self, and
563                  * OID (if any)
564                  */
565                 mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
566                 mtuple->t_self = tuple->t_self;
567                 mtuple->t_tableOid = tuple->t_tableOid;
568                 if (rel->rd_att->tdhasoid)
569                         HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
570         }
571         else
572         {
573                 mtuple = NULL;
574                 SPI_result = SPI_ERROR_NOATTRIBUTE;
575         }
576
577         pfree(v);
578         pfree(n);
579
580         if (oldcxt)
581                 MemoryContextSwitchTo(oldcxt);
582
583         return mtuple;
584 }
585
586 int
587 SPI_fnumber(TupleDesc tupdesc, const char *fname)
588 {
589         int                     res;
590         Form_pg_attribute sysatt;
591
592         for (res = 0; res < tupdesc->natts; res++)
593         {
594                 if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0)
595                         return res + 1;
596         }
597
598         sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ );
599         if (sysatt != NULL)
600                 return sysatt->attnum;
601
602         /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
603         return SPI_ERROR_NOATTRIBUTE;
604 }
605
606 char *
607 SPI_fname(TupleDesc tupdesc, int fnumber)
608 {
609         Form_pg_attribute att;
610
611         SPI_result = 0;
612
613         if (fnumber > tupdesc->natts || fnumber == 0 ||
614                 fnumber <= FirstLowInvalidHeapAttributeNumber)
615         {
616                 SPI_result = SPI_ERROR_NOATTRIBUTE;
617                 return NULL;
618         }
619
620         if (fnumber > 0)
621                 att = tupdesc->attrs[fnumber - 1];
622         else
623                 att = SystemAttributeDefinition(fnumber, true);
624
625         return pstrdup(NameStr(att->attname));
626 }
627
628 char *
629 SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
630 {
631         char       *result;
632         Datum           origval,
633                                 val;
634         bool            isnull;
635         Oid                     typoid,
636                                 foutoid;
637         bool            typisvarlena;
638
639         SPI_result = 0;
640
641         if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||
642                 fnumber <= FirstLowInvalidHeapAttributeNumber)
643         {
644                 SPI_result = SPI_ERROR_NOATTRIBUTE;
645                 return NULL;
646         }
647
648         origval = heap_getattr(tuple, fnumber, tupdesc, &isnull);
649         if (isnull)
650                 return NULL;
651
652         if (fnumber > 0)
653                 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
654         else
655                 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
656
657         getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
658
659         /*
660          * If we have a toasted datum, forcibly detoast it here to avoid memory
661          * leakage inside the type's output routine.
662          */
663         if (typisvarlena)
664                 val = PointerGetDatum(PG_DETOAST_DATUM(origval));
665         else
666                 val = origval;
667
668         result = OidOutputFunctionCall(foutoid, val);
669
670         /* Clean up detoasted copy, if any */
671         if (val != origval)
672                 pfree(DatumGetPointer(val));
673
674         return result;
675 }
676
677 Datum
678 SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
679 {
680         SPI_result = 0;
681
682         if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||
683                 fnumber <= FirstLowInvalidHeapAttributeNumber)
684         {
685                 SPI_result = SPI_ERROR_NOATTRIBUTE;
686                 *isnull = true;
687                 return (Datum) NULL;
688         }
689
690         return heap_getattr(tuple, fnumber, tupdesc, isnull);
691 }
692
693 char *
694 SPI_gettype(TupleDesc tupdesc, int fnumber)
695 {
696         Oid                     typoid;
697         HeapTuple       typeTuple;
698         char       *result;
699
700         SPI_result = 0;
701
702         if (fnumber > tupdesc->natts || fnumber == 0 ||
703                 fnumber <= FirstLowInvalidHeapAttributeNumber)
704         {
705                 SPI_result = SPI_ERROR_NOATTRIBUTE;
706                 return NULL;
707         }
708
709         if (fnumber > 0)
710                 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
711         else
712                 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
713
714         typeTuple = SearchSysCache(TYPEOID,
715                                                            ObjectIdGetDatum(typoid),
716                                                            0, 0, 0);
717
718         if (!HeapTupleIsValid(typeTuple))
719         {
720                 SPI_result = SPI_ERROR_TYPUNKNOWN;
721                 return NULL;
722         }
723
724         result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
725         ReleaseSysCache(typeTuple);
726         return result;
727 }
728
729 Oid
730 SPI_gettypeid(TupleDesc tupdesc, int fnumber)
731 {
732         SPI_result = 0;
733
734         if (fnumber > tupdesc->natts || fnumber == 0 ||
735                 fnumber <= FirstLowInvalidHeapAttributeNumber)
736         {
737                 SPI_result = SPI_ERROR_NOATTRIBUTE;
738                 return InvalidOid;
739         }
740
741         if (fnumber > 0)
742                 return tupdesc->attrs[fnumber - 1]->atttypid;
743         else
744                 return (SystemAttributeDefinition(fnumber, true))->atttypid;
745 }
746
747 char *
748 SPI_getrelname(Relation rel)
749 {
750         return pstrdup(RelationGetRelationName(rel));
751 }
752
753 char *
754 SPI_getnspname(Relation rel)
755 {
756         return get_namespace_name(RelationGetNamespace(rel));
757 }
758
759 void *
760 SPI_palloc(Size size)
761 {
762         MemoryContext oldcxt = NULL;
763         void       *pointer;
764
765         if (_SPI_curid + 1 == _SPI_connected)           /* connected */
766         {
767                 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
768                         elog(ERROR, "SPI stack corrupted");
769                 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
770         }
771
772         pointer = palloc(size);
773
774         if (oldcxt)
775                 MemoryContextSwitchTo(oldcxt);
776
777         return pointer;
778 }
779
780 void *
781 SPI_repalloc(void *pointer, Size size)
782 {
783         /* No longer need to worry which context chunk was in... */
784         return repalloc(pointer, size);
785 }
786
787 void
788 SPI_pfree(void *pointer)
789 {
790         /* No longer need to worry which context chunk was in... */
791         pfree(pointer);
792 }
793
794 void
795 SPI_freetuple(HeapTuple tuple)
796 {
797         /* No longer need to worry which context tuple was in... */
798         heap_freetuple(tuple);
799 }
800
801 void
802 SPI_freetuptable(SPITupleTable *tuptable)
803 {
804         if (tuptable != NULL)
805                 MemoryContextDelete(tuptable->tuptabcxt);
806 }
807
808
809
810 /*
811  * SPI_cursor_open()
812  *
813  *      Open a prepared SPI plan as a portal
814  */
815 Portal
816 SPI_cursor_open(const char *name, void *plan,
817                                 Datum *Values, const char *Nulls,
818                                 bool read_only)
819 {
820         _SPI_plan  *spiplan = (_SPI_plan *) plan;
821         List       *qtlist;
822         List       *ptlist;
823         ParamListInfo paramLI;
824         Snapshot        snapshot;
825         MemoryContext oldcontext;
826         Portal          portal;
827         int                     k;
828
829         /*
830          * Check that the plan is something the Portal code will special-case
831          * as returning one tupleset.
832          */
833         if (!SPI_is_cursor_plan(spiplan))
834         {
835                 /* try to give a good error message */
836                 Query      *queryTree;
837
838                 if (list_length(spiplan->qtlist) != 1)
839                         ereport(ERROR,
840                                         (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
841                                          errmsg("cannot open multi-query plan as cursor")));
842                 queryTree = PortalListGetPrimaryQuery((List *) linitial(spiplan->qtlist));
843                 if (queryTree == NULL)
844                         ereport(ERROR,
845                                         (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
846                                          errmsg("cannot open empty query as cursor")));
847                 ereport(ERROR,
848                                 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
849                                  /* translator: %s is name of a SQL command, eg INSERT */
850                                  errmsg("cannot open %s query as cursor",
851                                                 CreateQueryTag(queryTree))));
852         }
853
854         Assert(list_length(spiplan->qtlist) == 1);
855         qtlist = (List *) linitial(spiplan->qtlist);
856         ptlist = spiplan->ptlist;
857         if (list_length(qtlist) != list_length(ptlist))
858                 elog(ERROR, "corrupted SPI plan lists");
859
860         /* Reset SPI result (note we deliberately don't touch lastoid) */
861         SPI_processed = 0;
862         SPI_tuptable = NULL;
863         _SPI_current->processed = 0;
864         _SPI_current->tuptable = NULL;
865
866         /* Create the portal */
867         if (name == NULL || name[0] == '\0')
868         {
869                 /* Use a random nonconflicting name */
870                 portal = CreateNewPortal();
871         }
872         else
873         {
874                 /* In this path, error if portal of same name already exists */
875                 portal = CreatePortal(name, false, false);
876         }
877
878         /* Switch to portal's memory and copy the parsetrees and plans to there */
879         oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
880         qtlist = copyObject(qtlist);
881         ptlist = copyObject(ptlist);
882
883         /* If the plan has parameters, set them up */
884         if (spiplan->nargs > 0)
885         {
886                 /* sizeof(ParamListInfoData) includes the first array element */
887                 paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
888                                                         (spiplan->nargs - 1) * sizeof(ParamExternData));
889                 paramLI->numParams = spiplan->nargs;
890
891                 for (k = 0; k < spiplan->nargs; k++)
892                 {
893                         ParamExternData *prm = &paramLI->params[k];
894
895                         prm->ptype = spiplan->argtypes[k];
896                         prm->isnull = (Nulls && Nulls[k] == 'n');
897                         if (prm->isnull)
898                         {
899                                 /* nulls just copy */
900                                 prm->value = Values[k];
901                         }
902                         else
903                         {
904                                 /* pass-by-ref values must be copied into portal context */
905                                 int16           paramTypLen;
906                                 bool            paramTypByVal;
907
908                                 get_typlenbyval(prm->ptype, &paramTypLen, &paramTypByVal);
909                                 prm->value = datumCopy(Values[k],
910                                                                            paramTypByVal, paramTypLen);
911                         }
912                 }
913         }
914         else
915                 paramLI = NULL;
916
917         /*
918          * Set up the portal.
919          */
920         PortalDefineQuery(portal,
921                                           NULL,         /* no statement name */
922                                           spiplan->query,
923                                           CreateQueryTag(PortalListGetPrimaryQuery(qtlist)),
924                                           qtlist,
925                                           ptlist,
926                                           PortalGetHeapMemory(portal));
927
928         MemoryContextSwitchTo(oldcontext);
929
930         /*
931          * Set up options for portal.
932          */
933         portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL);
934         if (list_length(ptlist) == 1 &&
935                 ExecSupportsBackwardScan((Plan *) linitial(ptlist)))
936                 portal->cursorOptions |= CURSOR_OPT_SCROLL;
937         else
938                 portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
939
940         /*
941          * Set up the snapshot to use.  (PortalStart will do CopySnapshot, so we
942          * skip that here.)
943          */
944         if (read_only)
945                 snapshot = ActiveSnapshot;
946         else
947         {
948                 CommandCounterIncrement();
949                 snapshot = GetTransactionSnapshot();
950         }
951
952         /*
953          * Start portal execution.
954          */
955         PortalStart(portal, paramLI, snapshot);
956
957         Assert(portal->strategy != PORTAL_MULTI_QUERY);
958
959         /* Return the created portal */
960         return portal;
961 }
962
963
964 /*
965  * SPI_cursor_find()
966  *
967  *      Find the portal of an existing open cursor
968  */
969 Portal
970 SPI_cursor_find(const char *name)
971 {
972         return GetPortalByName(name);
973 }
974
975
976 /*
977  * SPI_cursor_fetch()
978  *
979  *      Fetch rows in a cursor
980  */
981 void
982 SPI_cursor_fetch(Portal portal, bool forward, long count)
983 {
984         _SPI_cursor_operation(portal, forward, count,
985                                                   CreateDestReceiver(DestSPI, NULL));
986         /* we know that the DestSPI receiver doesn't need a destroy call */
987 }
988
989
990 /*
991  * SPI_cursor_move()
992  *
993  *      Move in a cursor
994  */
995 void
996 SPI_cursor_move(Portal portal, bool forward, long count)
997 {
998         _SPI_cursor_operation(portal, forward, count, None_Receiver);
999 }
1000
1001
1002 /*
1003  * SPI_cursor_close()
1004  *
1005  *      Close a cursor
1006  */
1007 void
1008 SPI_cursor_close(Portal portal)
1009 {
1010         if (!PortalIsValid(portal))
1011                 elog(ERROR, "invalid portal in SPI cursor operation");
1012
1013         PortalDrop(portal, false);
1014 }
1015
1016 /*
1017  * Returns the Oid representing the type id for argument at argIndex. First
1018  * parameter is at index zero.
1019  */
1020 Oid
1021 SPI_getargtypeid(void *plan, int argIndex)
1022 {
1023         if (plan == NULL || argIndex < 0 || argIndex >= ((_SPI_plan *) plan)->nargs)
1024         {
1025                 SPI_result = SPI_ERROR_ARGUMENT;
1026                 return InvalidOid;
1027         }
1028         return ((_SPI_plan *) plan)->argtypes[argIndex];
1029 }
1030
1031 /*
1032  * Returns the number of arguments for the prepared plan.
1033  */
1034 int
1035 SPI_getargcount(void *plan)
1036 {
1037         if (plan == NULL)
1038         {
1039                 SPI_result = SPI_ERROR_ARGUMENT;
1040                 return -1;
1041         }
1042         return ((_SPI_plan *) plan)->nargs;
1043 }
1044
1045 /*
1046  * Returns true if the plan contains exactly one command
1047  * and that command returns tuples to the caller (eg, SELECT or
1048  * INSERT ... RETURNING, but not SELECT ... INTO). In essence,
1049  * the result indicates if the command can be used with SPI_cursor_open
1050  *
1051  * Parameters
1052  *        plan: A plan previously prepared using SPI_prepare
1053  */
1054 bool
1055 SPI_is_cursor_plan(void *plan)
1056 {
1057         _SPI_plan  *spiplan = (_SPI_plan *) plan;
1058
1059         if (spiplan == NULL)
1060         {
1061                 SPI_result = SPI_ERROR_ARGUMENT;
1062                 return false;
1063         }
1064
1065         if (list_length(spiplan->qtlist) != 1)
1066                 return false;                   /* not exactly 1 pre-rewrite command */
1067
1068         switch (ChoosePortalStrategy((List *) linitial(spiplan->qtlist)))
1069         {
1070                 case PORTAL_ONE_SELECT:
1071                 case PORTAL_ONE_RETURNING:
1072                 case PORTAL_UTIL_SELECT:
1073                         /* OK */
1074                         return true;
1075
1076                 case PORTAL_MULTI_QUERY:
1077                         /* will not return tuples */
1078                         break;
1079         }
1080         return false;
1081 }
1082
1083 /*
1084  * SPI_result_code_string --- convert any SPI return code to a string
1085  *
1086  * This is often useful in error messages.      Most callers will probably
1087  * only pass negative (error-case) codes, but for generality we recognize
1088  * the success codes too.
1089  */
1090 const char *
1091 SPI_result_code_string(int code)
1092 {
1093         static char buf[64];
1094
1095         switch (code)
1096         {
1097                 case SPI_ERROR_CONNECT:
1098                         return "SPI_ERROR_CONNECT";
1099                 case SPI_ERROR_COPY:
1100                         return "SPI_ERROR_COPY";
1101                 case SPI_ERROR_OPUNKNOWN:
1102                         return "SPI_ERROR_OPUNKNOWN";
1103                 case SPI_ERROR_UNCONNECTED:
1104                         return "SPI_ERROR_UNCONNECTED";
1105                 case SPI_ERROR_CURSOR:
1106                         return "SPI_ERROR_CURSOR";
1107                 case SPI_ERROR_ARGUMENT:
1108                         return "SPI_ERROR_ARGUMENT";
1109                 case SPI_ERROR_PARAM:
1110                         return "SPI_ERROR_PARAM";
1111                 case SPI_ERROR_TRANSACTION:
1112                         return "SPI_ERROR_TRANSACTION";
1113                 case SPI_ERROR_NOATTRIBUTE:
1114                         return "SPI_ERROR_NOATTRIBUTE";
1115                 case SPI_ERROR_NOOUTFUNC:
1116                         return "SPI_ERROR_NOOUTFUNC";
1117                 case SPI_ERROR_TYPUNKNOWN:
1118                         return "SPI_ERROR_TYPUNKNOWN";
1119                 case SPI_OK_CONNECT:
1120                         return "SPI_OK_CONNECT";
1121                 case SPI_OK_FINISH:
1122                         return "SPI_OK_FINISH";
1123                 case SPI_OK_FETCH:
1124                         return "SPI_OK_FETCH";
1125                 case SPI_OK_UTILITY:
1126                         return "SPI_OK_UTILITY";
1127                 case SPI_OK_SELECT:
1128                         return "SPI_OK_SELECT";
1129                 case SPI_OK_SELINTO:
1130                         return "SPI_OK_SELINTO";
1131                 case SPI_OK_INSERT:
1132                         return "SPI_OK_INSERT";
1133                 case SPI_OK_DELETE:
1134                         return "SPI_OK_DELETE";
1135                 case SPI_OK_UPDATE:
1136                         return "SPI_OK_UPDATE";
1137                 case SPI_OK_CURSOR:
1138                         return "SPI_OK_CURSOR";
1139         }
1140         /* Unrecognized code ... return something useful ... */
1141         sprintf(buf, "Unrecognized SPI code %d", code);
1142         return buf;
1143 }
1144
1145 /* =================== private functions =================== */
1146
1147 /*
1148  * spi_dest_startup
1149  *              Initialize to receive tuples from Executor into SPITupleTable
1150  *              of current SPI procedure
1151  */
1152 void
1153 spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
1154 {
1155         SPITupleTable *tuptable;
1156         MemoryContext oldcxt;
1157         MemoryContext tuptabcxt;
1158
1159         /*
1160          * When called by Executor _SPI_curid expected to be equal to
1161          * _SPI_connected
1162          */
1163         if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1164                 elog(ERROR, "improper call to spi_dest_startup");
1165         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1166                 elog(ERROR, "SPI stack corrupted");
1167
1168         if (_SPI_current->tuptable != NULL)
1169                 elog(ERROR, "improper call to spi_dest_startup");
1170
1171         oldcxt = _SPI_procmem();        /* switch to procedure memory context */
1172
1173         tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,
1174                                                                           "SPI TupTable",
1175                                                                           ALLOCSET_DEFAULT_MINSIZE,
1176                                                                           ALLOCSET_DEFAULT_INITSIZE,
1177                                                                           ALLOCSET_DEFAULT_MAXSIZE);
1178         MemoryContextSwitchTo(tuptabcxt);
1179
1180         _SPI_current->tuptable = tuptable = (SPITupleTable *)
1181                 palloc(sizeof(SPITupleTable));
1182         tuptable->tuptabcxt = tuptabcxt;
1183         tuptable->alloced = tuptable->free = 128;
1184         tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
1185         tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
1186
1187         MemoryContextSwitchTo(oldcxt);
1188 }
1189
1190 /*
1191  * spi_printtup
1192  *              store tuple retrieved by Executor into SPITupleTable
1193  *              of current SPI procedure
1194  */
1195 void
1196 spi_printtup(TupleTableSlot *slot, DestReceiver *self)
1197 {
1198         SPITupleTable *tuptable;
1199         MemoryContext oldcxt;
1200
1201         /*
1202          * When called by Executor _SPI_curid expected to be equal to
1203          * _SPI_connected
1204          */
1205         if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1206                 elog(ERROR, "improper call to spi_printtup");
1207         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1208                 elog(ERROR, "SPI stack corrupted");
1209
1210         tuptable = _SPI_current->tuptable;
1211         if (tuptable == NULL)
1212                 elog(ERROR, "improper call to spi_printtup");
1213
1214         oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
1215
1216         if (tuptable->free == 0)
1217         {
1218                 tuptable->free = 256;
1219                 tuptable->alloced += tuptable->free;
1220                 tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
1221                                                                           tuptable->alloced * sizeof(HeapTuple));
1222         }
1223
1224         tuptable->vals[tuptable->alloced - tuptable->free] =
1225                 ExecCopySlotTuple(slot);
1226         (tuptable->free)--;
1227
1228         MemoryContextSwitchTo(oldcxt);
1229 }
1230
1231 /*
1232  * Static functions
1233  */
1234
1235 /*
1236  * Parse and plan a querystring.
1237  *
1238  * At entry, plan->argtypes and plan->nargs must be valid.
1239  *
1240  * Query and plan lists are stored into *plan.
1241  */
1242 static void
1243 _SPI_prepare_plan(const char *src, _SPI_plan *plan)
1244 {
1245         List       *raw_parsetree_list;
1246         List       *query_list_list;
1247         List       *plan_list;
1248         ListCell   *list_item;
1249         ErrorContextCallback spierrcontext;
1250         Oid                *argtypes = plan->argtypes;
1251         int                     nargs = plan->nargs;
1252
1253         /*
1254          * Increment CommandCounter to see changes made by now.  We must do this
1255          * to be sure of seeing any schema changes made by a just-preceding SPI
1256          * command.  (But we don't bother advancing the snapshot, since the
1257          * planner generally operates under SnapshotNow rules anyway.)
1258          */
1259         CommandCounterIncrement();
1260
1261         /*
1262          * Setup error traceback support for ereport()
1263          */
1264         spierrcontext.callback = _SPI_error_callback;
1265         spierrcontext.arg = (void *) src;
1266         spierrcontext.previous = error_context_stack;
1267         error_context_stack = &spierrcontext;
1268
1269         /*
1270          * Parse the request string into a list of raw parse trees.
1271          */
1272         raw_parsetree_list = pg_parse_query(src);
1273
1274         /*
1275          * Do parse analysis and rule rewrite for each raw parsetree.
1276          *
1277          * We save the querytrees from each raw parsetree as a separate sublist.
1278          * This allows _SPI_execute_plan() to know where the boundaries between
1279          * original queries fall.
1280          */
1281         query_list_list = NIL;
1282         plan_list = NIL;
1283
1284         foreach(list_item, raw_parsetree_list)
1285         {
1286                 Node       *parsetree = (Node *) lfirst(list_item);
1287                 List       *query_list;
1288
1289                 query_list = pg_analyze_and_rewrite(parsetree, src, argtypes, nargs);
1290
1291                 query_list_list = lappend(query_list_list, query_list);
1292
1293                 plan_list = list_concat(plan_list,
1294                                                                 pg_plan_queries(query_list, NULL, false));
1295         }
1296
1297         plan->qtlist = query_list_list;
1298         plan->ptlist = plan_list;
1299
1300         /*
1301          * Pop the error context stack
1302          */
1303         error_context_stack = spierrcontext.previous;
1304 }
1305
1306 /*
1307  * Execute the given plan with the given parameter values
1308  *
1309  * snapshot: query snapshot to use, or InvalidSnapshot for the normal
1310  *              behavior of taking a new snapshot for each query.
1311  * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
1312  * read_only: TRUE for read-only execution (no CommandCounterIncrement)
1313  * tcount: execution tuple-count limit, or 0 for none
1314  */
1315 static int
1316 _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
1317                                   Snapshot snapshot, Snapshot crosscheck_snapshot,
1318                                   bool read_only, long tcount)
1319 {
1320         volatile int my_res = 0;
1321         volatile uint32 my_processed = 0;
1322         volatile Oid my_lastoid = InvalidOid;
1323         SPITupleTable *volatile my_tuptable = NULL;
1324         Snapshot        saveActiveSnapshot;
1325
1326         /* Be sure to restore ActiveSnapshot on error exit */
1327         saveActiveSnapshot = ActiveSnapshot;
1328         PG_TRY();
1329         {
1330                 List       *query_list_list = plan->qtlist;
1331                 ListCell   *plan_list_item = list_head(plan->ptlist);
1332                 ListCell   *query_list_list_item;
1333                 ErrorContextCallback spierrcontext;
1334                 int                     nargs = plan->nargs;
1335                 ParamListInfo paramLI;
1336
1337                 /* Convert parameters to form wanted by executor */
1338                 if (nargs > 0)
1339                 {
1340                         int                     k;
1341
1342                         /* sizeof(ParamListInfoData) includes the first array element */
1343                         paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
1344                                                                          (nargs - 1) * sizeof(ParamExternData));
1345                         paramLI->numParams = nargs;
1346
1347                         for (k = 0; k < nargs; k++)
1348                         {
1349                                 ParamExternData *prm = &paramLI->params[k];
1350
1351                                 prm->value = Values[k];
1352                                 prm->isnull = (Nulls && Nulls[k] == 'n');
1353                                 prm->ptype = plan->argtypes[k];
1354                         }
1355                 }
1356                 else
1357                         paramLI = NULL;
1358
1359                 /*
1360                  * Setup error traceback support for ereport()
1361                  */
1362                 spierrcontext.callback = _SPI_error_callback;
1363                 spierrcontext.arg = (void *) plan->query;
1364                 spierrcontext.previous = error_context_stack;
1365                 error_context_stack = &spierrcontext;
1366
1367                 foreach(query_list_list_item, query_list_list)
1368                 {
1369                         List       *query_list = lfirst(query_list_list_item);
1370                         ListCell   *query_list_item;
1371
1372                         foreach(query_list_item, query_list)
1373                         {
1374                                 Query      *queryTree = (Query *) lfirst(query_list_item);
1375                                 Plan       *planTree;
1376                                 QueryDesc  *qdesc;
1377                                 DestReceiver *dest;
1378                                 int                     res;
1379
1380                                 planTree = lfirst(plan_list_item);
1381                                 plan_list_item = lnext(plan_list_item);
1382
1383                                 _SPI_current->processed = 0;
1384                                 _SPI_current->lastoid = InvalidOid;
1385                                 _SPI_current->tuptable = NULL;
1386
1387                                 if (queryTree->commandType == CMD_UTILITY)
1388                                 {
1389                                         if (IsA(queryTree->utilityStmt, CopyStmt))
1390                                         {
1391                                                 CopyStmt   *stmt = (CopyStmt *) queryTree->utilityStmt;
1392
1393                                                 if (stmt->filename == NULL)
1394                                                 {
1395                                                         my_res = SPI_ERROR_COPY;
1396                                                         goto fail;
1397                                                 }
1398                                         }
1399                                         else if (IsA(queryTree->utilityStmt, DeclareCursorStmt) ||
1400                                                          IsA(queryTree->utilityStmt, ClosePortalStmt) ||
1401                                                          IsA(queryTree->utilityStmt, FetchStmt))
1402                                         {
1403                                                 my_res = SPI_ERROR_CURSOR;
1404                                                 goto fail;
1405                                         }
1406                                         else if (IsA(queryTree->utilityStmt, TransactionStmt))
1407                                         {
1408                                                 my_res = SPI_ERROR_TRANSACTION;
1409                                                 goto fail;
1410                                         }
1411                                 }
1412
1413                                 if (read_only && !QueryIsReadOnly(queryTree))
1414                                         ereport(ERROR,
1415                                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1416                                         /* translator: %s is a SQL statement name */
1417                                            errmsg("%s is not allowed in a non-volatile function",
1418                                                           CreateQueryTag(queryTree))));
1419
1420                                 /*
1421                                  * If not read-only mode, advance the command counter before
1422                                  * each command.
1423                                  */
1424                                 if (!read_only)
1425                                         CommandCounterIncrement();
1426
1427                                 dest = CreateDestReceiver(queryTree->canSetTag ? DestSPI : DestNone,
1428                                                                                   NULL);
1429
1430                                 if (snapshot == InvalidSnapshot)
1431                                 {
1432                                         /*
1433                                          * Default read_only behavior is to use the entry-time
1434                                          * ActiveSnapshot; if read-write, grab a full new snap.
1435                                          */
1436                                         if (read_only)
1437                                                 ActiveSnapshot = CopySnapshot(saveActiveSnapshot);
1438                                         else
1439                                                 ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
1440                                 }
1441                                 else
1442                                 {
1443                                         /*
1444                                          * We interpret read_only with a specified snapshot to be
1445                                          * exactly that snapshot, but read-write means use the
1446                                          * snap with advancing of command ID.
1447                                          */
1448                                         ActiveSnapshot = CopySnapshot(snapshot);
1449                                         if (!read_only)
1450                                                 ActiveSnapshot->curcid = GetCurrentCommandId();
1451                                 }
1452
1453                                 if (queryTree->commandType == CMD_UTILITY)
1454                                 {
1455                                         ProcessUtility(queryTree->utilityStmt, paramLI,
1456                                                                    dest, NULL);
1457                                         res = SPI_OK_UTILITY;
1458                                 }
1459                                 else
1460                                 {
1461                                         qdesc = CreateQueryDesc(queryTree, planTree,
1462                                                                                         ActiveSnapshot,
1463                                                                                         crosscheck_snapshot,
1464                                                                                         dest,
1465                                                                                         paramLI, false);
1466                                         res = _SPI_pquery(qdesc,
1467                                                                           queryTree->canSetTag ? tcount : 0);
1468                                         FreeQueryDesc(qdesc);
1469                                 }
1470                                 FreeSnapshot(ActiveSnapshot);
1471                                 ActiveSnapshot = NULL;
1472
1473                                 /*
1474                                  * The last canSetTag query sets the status values returned
1475                                  * to the caller.  Be careful to free any tuptables not
1476                                  * returned, to avoid intratransaction memory leak.
1477                                  */
1478                                 if (queryTree->canSetTag)
1479                                 {
1480                                         my_processed = _SPI_current->processed;
1481                                         my_lastoid = _SPI_current->lastoid;
1482                                         SPI_freetuptable(my_tuptable);
1483                                         my_tuptable = _SPI_current->tuptable;
1484                                         my_res = res;
1485                                 }
1486                                 else
1487                                 {
1488                                         SPI_freetuptable(_SPI_current->tuptable);
1489                                         _SPI_current->tuptable = NULL;
1490                                 }
1491                                 /* we know that the receiver doesn't need a destroy call */
1492                                 if (res < 0)
1493                                 {
1494                                         my_res = res;
1495                                         goto fail;
1496                                 }
1497                         }
1498                 }
1499
1500 fail:
1501
1502                 /*
1503                  * Pop the error context stack
1504                  */
1505                 error_context_stack = spierrcontext.previous;
1506         }
1507         PG_CATCH();
1508         {
1509                 /* Restore global vars and propagate error */
1510                 ActiveSnapshot = saveActiveSnapshot;
1511                 PG_RE_THROW();
1512         }
1513         PG_END_TRY();
1514
1515         ActiveSnapshot = saveActiveSnapshot;
1516
1517         /* Save results for caller */
1518         SPI_processed = my_processed;
1519         SPI_lastoid = my_lastoid;
1520         SPI_tuptable = my_tuptable;
1521
1522         return my_res;
1523 }
1524
1525 static int
1526 _SPI_pquery(QueryDesc *queryDesc, long tcount)
1527 {
1528         int                     operation = queryDesc->operation;
1529         int                     res;
1530
1531         switch (operation)
1532         {
1533                 case CMD_SELECT:
1534                         if (queryDesc->parsetree->into)         /* select into table? */
1535                                 res = SPI_OK_SELINTO;
1536                         else if (queryDesc->dest->mydest != DestSPI)
1537                         {
1538                                 /* Don't return SPI_OK_SELECT if we're discarding result */
1539                                 res = SPI_OK_UTILITY;
1540                         }
1541                         else
1542                                 res = SPI_OK_SELECT;
1543                         break;
1544                 case CMD_INSERT:
1545                         res = SPI_OK_INSERT;
1546                         break;
1547                 case CMD_DELETE:
1548                         res = SPI_OK_DELETE;
1549                         break;
1550                 case CMD_UPDATE:
1551                         res = SPI_OK_UPDATE;
1552                         break;
1553                 default:
1554                         return SPI_ERROR_OPUNKNOWN;
1555         }
1556
1557 #ifdef SPI_EXECUTOR_STATS
1558         if (ShowExecutorStats)
1559                 ResetUsage();
1560 #endif
1561
1562         AfterTriggerBeginQuery();
1563
1564         ExecutorStart(queryDesc, 0);
1565
1566         ExecutorRun(queryDesc, ForwardScanDirection, tcount);
1567
1568         _SPI_current->processed = queryDesc->estate->es_processed;
1569         _SPI_current->lastoid = queryDesc->estate->es_lastoid;
1570
1571         if (operation == CMD_SELECT && queryDesc->dest->mydest == DestSPI)
1572         {
1573                 if (_SPI_checktuples())
1574                         elog(ERROR, "consistency check on SPI tuple count failed");
1575         }
1576
1577         /* Take care of any queued AFTER triggers */
1578         AfterTriggerEndQuery(queryDesc->estate);
1579
1580         ExecutorEnd(queryDesc);
1581
1582 #ifdef SPI_EXECUTOR_STATS
1583         if (ShowExecutorStats)
1584                 ShowUsage("SPI EXECUTOR STATS");
1585 #endif
1586
1587         return res;
1588 }
1589
1590 /*
1591  * _SPI_error_callback
1592  *
1593  * Add context information when a query invoked via SPI fails
1594  */
1595 static void
1596 _SPI_error_callback(void *arg)
1597 {
1598         const char *query = (const char *) arg;
1599         int                     syntaxerrposition;
1600
1601         /*
1602          * If there is a syntax error position, convert to internal syntax error;
1603          * otherwise treat the query as an item of context stack
1604          */
1605         syntaxerrposition = geterrposition();
1606         if (syntaxerrposition > 0)
1607         {
1608                 errposition(0);
1609                 internalerrposition(syntaxerrposition);
1610                 internalerrquery(query);
1611         }
1612         else
1613                 errcontext("SQL statement \"%s\"", query);
1614 }
1615
1616 /*
1617  * _SPI_cursor_operation()
1618  *
1619  *      Do a FETCH or MOVE in a cursor
1620  */
1621 static void
1622 _SPI_cursor_operation(Portal portal, bool forward, long count,
1623                                           DestReceiver *dest)
1624 {
1625         long            nfetched;
1626
1627         /* Check that the portal is valid */
1628         if (!PortalIsValid(portal))
1629                 elog(ERROR, "invalid portal in SPI cursor operation");
1630
1631         /* Push the SPI stack */
1632         if (_SPI_begin_call(true) < 0)
1633                 elog(ERROR, "SPI cursor operation called while not connected");
1634
1635         /* Reset the SPI result (note we deliberately don't touch lastoid) */
1636         SPI_processed = 0;
1637         SPI_tuptable = NULL;
1638         _SPI_current->processed = 0;
1639         _SPI_current->tuptable = NULL;
1640
1641         /* Run the cursor */
1642         nfetched = PortalRunFetch(portal,
1643                                                           forward ? FETCH_FORWARD : FETCH_BACKWARD,
1644                                                           count,
1645                                                           dest);
1646
1647         /*
1648          * Think not to combine this store with the preceding function call. If
1649          * the portal contains calls to functions that use SPI, then SPI_stack is
1650          * likely to move around while the portal runs.  When control returns,
1651          * _SPI_current will point to the correct stack entry... but the pointer
1652          * may be different than it was beforehand. So we must be sure to re-fetch
1653          * the pointer after the function call completes.
1654          */
1655         _SPI_current->processed = nfetched;
1656
1657         if (dest->mydest == DestSPI && _SPI_checktuples())
1658                 elog(ERROR, "consistency check on SPI tuple count failed");
1659
1660         /* Put the result into place for access by caller */
1661         SPI_processed = _SPI_current->processed;
1662         SPI_tuptable = _SPI_current->tuptable;
1663
1664         /* Pop the SPI stack */
1665         _SPI_end_call(true);
1666 }
1667
1668
1669 static MemoryContext
1670 _SPI_execmem(void)
1671 {
1672         return MemoryContextSwitchTo(_SPI_current->execCxt);
1673 }
1674
1675 static MemoryContext
1676 _SPI_procmem(void)
1677 {
1678         return MemoryContextSwitchTo(_SPI_current->procCxt);
1679 }
1680
1681 /*
1682  * _SPI_begin_call: begin a SPI operation within a connected procedure
1683  */
1684 static int
1685 _SPI_begin_call(bool execmem)
1686 {
1687         if (_SPI_curid + 1 != _SPI_connected)
1688                 return SPI_ERROR_UNCONNECTED;
1689         _SPI_curid++;
1690         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1691                 elog(ERROR, "SPI stack corrupted");
1692
1693         if (execmem)                            /* switch to the Executor memory context */
1694                 _SPI_execmem();
1695
1696         return 0;
1697 }
1698
1699 /*
1700  * _SPI_end_call: end a SPI operation within a connected procedure
1701  *
1702  * Note: this currently has no failure return cases, so callers don't check
1703  */
1704 static int
1705 _SPI_end_call(bool procmem)
1706 {
1707         /*
1708          * We're returning to procedure where _SPI_curid == _SPI_connected - 1
1709          */
1710         _SPI_curid--;
1711
1712         if (procmem)                            /* switch to the procedure memory context */
1713         {
1714                 _SPI_procmem();
1715                 /* and free Executor memory */
1716                 MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
1717         }
1718
1719         return 0;
1720 }
1721
1722 static bool
1723 _SPI_checktuples(void)
1724 {
1725         uint32          processed = _SPI_current->processed;
1726         SPITupleTable *tuptable = _SPI_current->tuptable;
1727         bool            failed = false;
1728
1729         if (tuptable == NULL)           /* spi_dest_startup was not called */
1730                 failed = true;
1731         else if (processed != (tuptable->alloced - tuptable->free))
1732                 failed = true;
1733
1734         return failed;
1735 }
1736
1737 static _SPI_plan *
1738 _SPI_copy_plan(_SPI_plan *plan, int location)
1739 {
1740         _SPI_plan  *newplan;
1741         MemoryContext oldcxt;
1742         MemoryContext plancxt;
1743         MemoryContext parentcxt;
1744
1745         /* Determine correct parent for the plan's memory context */
1746         if (location == _SPI_CPLAN_PROCXT)
1747                 parentcxt = _SPI_current->procCxt;
1748         else if (location == _SPI_CPLAN_TOPCXT)
1749                 parentcxt = TopMemoryContext;
1750         else
1751                 /* (this case not currently used) */
1752                 parentcxt = CurrentMemoryContext;
1753
1754         /*
1755          * Create a memory context for the plan.  We don't expect the plan to be
1756          * very large, so use smaller-than-default alloc parameters.
1757          */
1758         plancxt = AllocSetContextCreate(parentcxt,
1759                                                                         "SPI Plan",
1760                                                                         ALLOCSET_SMALL_MINSIZE,
1761                                                                         ALLOCSET_SMALL_INITSIZE,
1762                                                                         ALLOCSET_SMALL_MAXSIZE);
1763         oldcxt = MemoryContextSwitchTo(plancxt);
1764
1765         /* Copy the SPI plan into its own context */
1766         newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
1767         newplan->plancxt = plancxt;
1768         newplan->query = pstrdup(plan->query);
1769         newplan->qtlist = (List *) copyObject(plan->qtlist);
1770         newplan->ptlist = (List *) copyObject(plan->ptlist);
1771         newplan->nargs = plan->nargs;
1772         if (plan->nargs > 0)
1773         {
1774                 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
1775                 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
1776         }
1777         else
1778                 newplan->argtypes = NULL;
1779
1780         MemoryContextSwitchTo(oldcxt);
1781
1782         return newplan;
1783 }