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