]> granicus.if.org Git - postgresql/blob - src/backend/executor/spi.c
Add new return codes SPI_OK_INSERT_RETURNING etc to the SPI API.
[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.158 2006/08/27 23:47:57 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                 case SPI_OK_INSERT_RETURNING:
1140                         return "SPI_OK_INSERT_RETURNING";
1141                 case SPI_OK_DELETE_RETURNING:
1142                         return "SPI_OK_DELETE_RETURNING";
1143                 case SPI_OK_UPDATE_RETURNING:
1144                         return "SPI_OK_UPDATE_RETURNING";
1145         }
1146         /* Unrecognized code ... return something useful ... */
1147         sprintf(buf, "Unrecognized SPI code %d", code);
1148         return buf;
1149 }
1150
1151 /* =================== private functions =================== */
1152
1153 /*
1154  * spi_dest_startup
1155  *              Initialize to receive tuples from Executor into SPITupleTable
1156  *              of current SPI procedure
1157  */
1158 void
1159 spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
1160 {
1161         SPITupleTable *tuptable;
1162         MemoryContext oldcxt;
1163         MemoryContext tuptabcxt;
1164
1165         /*
1166          * When called by Executor _SPI_curid expected to be equal to
1167          * _SPI_connected
1168          */
1169         if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1170                 elog(ERROR, "improper call to spi_dest_startup");
1171         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1172                 elog(ERROR, "SPI stack corrupted");
1173
1174         if (_SPI_current->tuptable != NULL)
1175                 elog(ERROR, "improper call to spi_dest_startup");
1176
1177         oldcxt = _SPI_procmem();        /* switch to procedure memory context */
1178
1179         tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,
1180                                                                           "SPI TupTable",
1181                                                                           ALLOCSET_DEFAULT_MINSIZE,
1182                                                                           ALLOCSET_DEFAULT_INITSIZE,
1183                                                                           ALLOCSET_DEFAULT_MAXSIZE);
1184         MemoryContextSwitchTo(tuptabcxt);
1185
1186         _SPI_current->tuptable = tuptable = (SPITupleTable *)
1187                 palloc(sizeof(SPITupleTable));
1188         tuptable->tuptabcxt = tuptabcxt;
1189         tuptable->alloced = tuptable->free = 128;
1190         tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
1191         tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
1192
1193         MemoryContextSwitchTo(oldcxt);
1194 }
1195
1196 /*
1197  * spi_printtup
1198  *              store tuple retrieved by Executor into SPITupleTable
1199  *              of current SPI procedure
1200  */
1201 void
1202 spi_printtup(TupleTableSlot *slot, DestReceiver *self)
1203 {
1204         SPITupleTable *tuptable;
1205         MemoryContext oldcxt;
1206
1207         /*
1208          * When called by Executor _SPI_curid expected to be equal to
1209          * _SPI_connected
1210          */
1211         if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1212                 elog(ERROR, "improper call to spi_printtup");
1213         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1214                 elog(ERROR, "SPI stack corrupted");
1215
1216         tuptable = _SPI_current->tuptable;
1217         if (tuptable == NULL)
1218                 elog(ERROR, "improper call to spi_printtup");
1219
1220         oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
1221
1222         if (tuptable->free == 0)
1223         {
1224                 tuptable->free = 256;
1225                 tuptable->alloced += tuptable->free;
1226                 tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
1227                                                                           tuptable->alloced * sizeof(HeapTuple));
1228         }
1229
1230         tuptable->vals[tuptable->alloced - tuptable->free] =
1231                 ExecCopySlotTuple(slot);
1232         (tuptable->free)--;
1233
1234         MemoryContextSwitchTo(oldcxt);
1235 }
1236
1237 /*
1238  * Static functions
1239  */
1240
1241 /*
1242  * Parse and plan a querystring.
1243  *
1244  * At entry, plan->argtypes and plan->nargs must be valid.
1245  *
1246  * Query and plan lists are stored into *plan.
1247  */
1248 static void
1249 _SPI_prepare_plan(const char *src, _SPI_plan *plan)
1250 {
1251         List       *raw_parsetree_list;
1252         List       *query_list_list;
1253         List       *plan_list;
1254         ListCell   *list_item;
1255         ErrorContextCallback spierrcontext;
1256         Oid                *argtypes = plan->argtypes;
1257         int                     nargs = plan->nargs;
1258
1259         /*
1260          * Increment CommandCounter to see changes made by now.  We must do this
1261          * to be sure of seeing any schema changes made by a just-preceding SPI
1262          * command.  (But we don't bother advancing the snapshot, since the
1263          * planner generally operates under SnapshotNow rules anyway.)
1264          */
1265         CommandCounterIncrement();
1266
1267         /*
1268          * Setup error traceback support for ereport()
1269          */
1270         spierrcontext.callback = _SPI_error_callback;
1271         spierrcontext.arg = (void *) src;
1272         spierrcontext.previous = error_context_stack;
1273         error_context_stack = &spierrcontext;
1274
1275         /*
1276          * Parse the request string into a list of raw parse trees.
1277          */
1278         raw_parsetree_list = pg_parse_query(src);
1279
1280         /*
1281          * Do parse analysis and rule rewrite for each raw parsetree.
1282          *
1283          * We save the querytrees from each raw parsetree as a separate sublist.
1284          * This allows _SPI_execute_plan() to know where the boundaries between
1285          * original queries fall.
1286          */
1287         query_list_list = NIL;
1288         plan_list = NIL;
1289
1290         foreach(list_item, raw_parsetree_list)
1291         {
1292                 Node       *parsetree = (Node *) lfirst(list_item);
1293                 List       *query_list;
1294
1295                 query_list = pg_analyze_and_rewrite(parsetree, src, argtypes, nargs);
1296
1297                 query_list_list = lappend(query_list_list, query_list);
1298
1299                 plan_list = list_concat(plan_list,
1300                                                                 pg_plan_queries(query_list, NULL, false));
1301         }
1302
1303         plan->qtlist = query_list_list;
1304         plan->ptlist = plan_list;
1305
1306         /*
1307          * Pop the error context stack
1308          */
1309         error_context_stack = spierrcontext.previous;
1310 }
1311
1312 /*
1313  * Execute the given plan with the given parameter values
1314  *
1315  * snapshot: query snapshot to use, or InvalidSnapshot for the normal
1316  *              behavior of taking a new snapshot for each query.
1317  * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
1318  * read_only: TRUE for read-only execution (no CommandCounterIncrement)
1319  * tcount: execution tuple-count limit, or 0 for none
1320  */
1321 static int
1322 _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
1323                                   Snapshot snapshot, Snapshot crosscheck_snapshot,
1324                                   bool read_only, long tcount)
1325 {
1326         volatile int my_res = 0;
1327         volatile uint32 my_processed = 0;
1328         volatile Oid my_lastoid = InvalidOid;
1329         SPITupleTable *volatile my_tuptable = NULL;
1330         Snapshot        saveActiveSnapshot;
1331
1332         /* Be sure to restore ActiveSnapshot on error exit */
1333         saveActiveSnapshot = ActiveSnapshot;
1334         PG_TRY();
1335         {
1336                 List       *query_list_list = plan->qtlist;
1337                 ListCell   *plan_list_item = list_head(plan->ptlist);
1338                 ListCell   *query_list_list_item;
1339                 ErrorContextCallback spierrcontext;
1340                 int                     nargs = plan->nargs;
1341                 ParamListInfo paramLI;
1342
1343                 /* Convert parameters to form wanted by executor */
1344                 if (nargs > 0)
1345                 {
1346                         int                     k;
1347
1348                         /* sizeof(ParamListInfoData) includes the first array element */
1349                         paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
1350                                                                          (nargs - 1) * sizeof(ParamExternData));
1351                         paramLI->numParams = nargs;
1352
1353                         for (k = 0; k < nargs; k++)
1354                         {
1355                                 ParamExternData *prm = &paramLI->params[k];
1356
1357                                 prm->value = Values[k];
1358                                 prm->isnull = (Nulls && Nulls[k] == 'n');
1359                                 prm->ptype = plan->argtypes[k];
1360                         }
1361                 }
1362                 else
1363                         paramLI = NULL;
1364
1365                 /*
1366                  * Setup error traceback support for ereport()
1367                  */
1368                 spierrcontext.callback = _SPI_error_callback;
1369                 spierrcontext.arg = (void *) plan->query;
1370                 spierrcontext.previous = error_context_stack;
1371                 error_context_stack = &spierrcontext;
1372
1373                 foreach(query_list_list_item, query_list_list)
1374                 {
1375                         List       *query_list = lfirst(query_list_list_item);
1376                         ListCell   *query_list_item;
1377
1378                         foreach(query_list_item, query_list)
1379                         {
1380                                 Query      *queryTree = (Query *) lfirst(query_list_item);
1381                                 Plan       *planTree;
1382                                 QueryDesc  *qdesc;
1383                                 DestReceiver *dest;
1384                                 int                     res;
1385
1386                                 planTree = lfirst(plan_list_item);
1387                                 plan_list_item = lnext(plan_list_item);
1388
1389                                 _SPI_current->processed = 0;
1390                                 _SPI_current->lastoid = InvalidOid;
1391                                 _SPI_current->tuptable = NULL;
1392
1393                                 if (queryTree->commandType == CMD_UTILITY)
1394                                 {
1395                                         if (IsA(queryTree->utilityStmt, CopyStmt))
1396                                         {
1397                                                 CopyStmt   *stmt = (CopyStmt *) queryTree->utilityStmt;
1398
1399                                                 if (stmt->filename == NULL)
1400                                                 {
1401                                                         my_res = SPI_ERROR_COPY;
1402                                                         goto fail;
1403                                                 }
1404                                         }
1405                                         else if (IsA(queryTree->utilityStmt, DeclareCursorStmt) ||
1406                                                          IsA(queryTree->utilityStmt, ClosePortalStmt) ||
1407                                                          IsA(queryTree->utilityStmt, FetchStmt))
1408                                         {
1409                                                 my_res = SPI_ERROR_CURSOR;
1410                                                 goto fail;
1411                                         }
1412                                         else if (IsA(queryTree->utilityStmt, TransactionStmt))
1413                                         {
1414                                                 my_res = SPI_ERROR_TRANSACTION;
1415                                                 goto fail;
1416                                         }
1417                                 }
1418
1419                                 if (read_only && !QueryIsReadOnly(queryTree))
1420                                         ereport(ERROR,
1421                                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1422                                         /* translator: %s is a SQL statement name */
1423                                            errmsg("%s is not allowed in a non-volatile function",
1424                                                           CreateQueryTag(queryTree))));
1425
1426                                 /*
1427                                  * If not read-only mode, advance the command counter before
1428                                  * each command.
1429                                  */
1430                                 if (!read_only)
1431                                         CommandCounterIncrement();
1432
1433                                 dest = CreateDestReceiver(queryTree->canSetTag ? DestSPI : DestNone,
1434                                                                                   NULL);
1435
1436                                 if (snapshot == InvalidSnapshot)
1437                                 {
1438                                         /*
1439                                          * Default read_only behavior is to use the entry-time
1440                                          * ActiveSnapshot; if read-write, grab a full new snap.
1441                                          */
1442                                         if (read_only)
1443                                                 ActiveSnapshot = CopySnapshot(saveActiveSnapshot);
1444                                         else
1445                                                 ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
1446                                 }
1447                                 else
1448                                 {
1449                                         /*
1450                                          * We interpret read_only with a specified snapshot to be
1451                                          * exactly that snapshot, but read-write means use the
1452                                          * snap with advancing of command ID.
1453                                          */
1454                                         ActiveSnapshot = CopySnapshot(snapshot);
1455                                         if (!read_only)
1456                                                 ActiveSnapshot->curcid = GetCurrentCommandId();
1457                                 }
1458
1459                                 if (queryTree->commandType == CMD_UTILITY)
1460                                 {
1461                                         ProcessUtility(queryTree->utilityStmt, paramLI,
1462                                                                    dest, NULL);
1463                                         /* Update "processed" if stmt returned tuples */
1464                                         if (_SPI_current->tuptable)
1465                                                 _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free;
1466                                         res = SPI_OK_UTILITY;
1467                                 }
1468                                 else
1469                                 {
1470                                         qdesc = CreateQueryDesc(queryTree, planTree,
1471                                                                                         ActiveSnapshot,
1472                                                                                         crosscheck_snapshot,
1473                                                                                         dest,
1474                                                                                         paramLI, false);
1475                                         res = _SPI_pquery(qdesc,
1476                                                                           queryTree->canSetTag ? tcount : 0);
1477                                         FreeQueryDesc(qdesc);
1478                                 }
1479                                 FreeSnapshot(ActiveSnapshot);
1480                                 ActiveSnapshot = NULL;
1481
1482                                 /*
1483                                  * The last canSetTag query sets the status values returned
1484                                  * to the caller.  Be careful to free any tuptables not
1485                                  * returned, to avoid intratransaction memory leak.
1486                                  */
1487                                 if (queryTree->canSetTag)
1488                                 {
1489                                         my_processed = _SPI_current->processed;
1490                                         my_lastoid = _SPI_current->lastoid;
1491                                         SPI_freetuptable(my_tuptable);
1492                                         my_tuptable = _SPI_current->tuptable;
1493                                         my_res = res;
1494                                 }
1495                                 else
1496                                 {
1497                                         SPI_freetuptable(_SPI_current->tuptable);
1498                                         _SPI_current->tuptable = NULL;
1499                                 }
1500                                 /* we know that the receiver doesn't need a destroy call */
1501                                 if (res < 0)
1502                                 {
1503                                         my_res = res;
1504                                         goto fail;
1505                                 }
1506                         }
1507                 }
1508
1509 fail:
1510
1511                 /*
1512                  * Pop the error context stack
1513                  */
1514                 error_context_stack = spierrcontext.previous;
1515         }
1516         PG_CATCH();
1517         {
1518                 /* Restore global vars and propagate error */
1519                 ActiveSnapshot = saveActiveSnapshot;
1520                 PG_RE_THROW();
1521         }
1522         PG_END_TRY();
1523
1524         ActiveSnapshot = saveActiveSnapshot;
1525
1526         /* Save results for caller */
1527         SPI_processed = my_processed;
1528         SPI_lastoid = my_lastoid;
1529         SPI_tuptable = my_tuptable;
1530
1531         return my_res;
1532 }
1533
1534 static int
1535 _SPI_pquery(QueryDesc *queryDesc, long tcount)
1536 {
1537         int                     operation = queryDesc->operation;
1538         int                     res;
1539
1540         switch (operation)
1541         {
1542                 case CMD_SELECT:
1543                         if (queryDesc->parsetree->into)         /* select into table? */
1544                                 res = SPI_OK_SELINTO;
1545                         else if (queryDesc->dest->mydest != DestSPI)
1546                         {
1547                                 /* Don't return SPI_OK_SELECT if we're discarding result */
1548                                 res = SPI_OK_UTILITY;
1549                         }
1550                         else
1551                                 res = SPI_OK_SELECT;
1552                         break;
1553                 case CMD_INSERT:
1554                         if (queryDesc->parsetree->returningList)
1555                                 res = SPI_OK_INSERT_RETURNING;
1556                         else
1557                                 res = SPI_OK_INSERT;
1558                         break;
1559                 case CMD_DELETE:
1560                         if (queryDesc->parsetree->returningList)
1561                                 res = SPI_OK_DELETE_RETURNING;
1562                         else
1563                                 res = SPI_OK_DELETE;
1564                         break;
1565                 case CMD_UPDATE:
1566                         if (queryDesc->parsetree->returningList)
1567                                 res = SPI_OK_UPDATE_RETURNING;
1568                         else
1569                                 res = SPI_OK_UPDATE;
1570                         break;
1571                 default:
1572                         return SPI_ERROR_OPUNKNOWN;
1573         }
1574
1575 #ifdef SPI_EXECUTOR_STATS
1576         if (ShowExecutorStats)
1577                 ResetUsage();
1578 #endif
1579
1580         AfterTriggerBeginQuery();
1581
1582         ExecutorStart(queryDesc, 0);
1583
1584         ExecutorRun(queryDesc, ForwardScanDirection, tcount);
1585
1586         _SPI_current->processed = queryDesc->estate->es_processed;
1587         _SPI_current->lastoid = queryDesc->estate->es_lastoid;
1588
1589         if ((res == SPI_OK_SELECT || queryDesc->parsetree->returningList) &&
1590                 queryDesc->dest->mydest == DestSPI)
1591         {
1592                 if (_SPI_checktuples())
1593                         elog(ERROR, "consistency check on SPI tuple count failed");
1594         }
1595
1596         /* Take care of any queued AFTER triggers */
1597         AfterTriggerEndQuery(queryDesc->estate);
1598
1599         ExecutorEnd(queryDesc);
1600
1601 #ifdef SPI_EXECUTOR_STATS
1602         if (ShowExecutorStats)
1603                 ShowUsage("SPI EXECUTOR STATS");
1604 #endif
1605
1606         return res;
1607 }
1608
1609 /*
1610  * _SPI_error_callback
1611  *
1612  * Add context information when a query invoked via SPI fails
1613  */
1614 static void
1615 _SPI_error_callback(void *arg)
1616 {
1617         const char *query = (const char *) arg;
1618         int                     syntaxerrposition;
1619
1620         /*
1621          * If there is a syntax error position, convert to internal syntax error;
1622          * otherwise treat the query as an item of context stack
1623          */
1624         syntaxerrposition = geterrposition();
1625         if (syntaxerrposition > 0)
1626         {
1627                 errposition(0);
1628                 internalerrposition(syntaxerrposition);
1629                 internalerrquery(query);
1630         }
1631         else
1632                 errcontext("SQL statement \"%s\"", query);
1633 }
1634
1635 /*
1636  * _SPI_cursor_operation()
1637  *
1638  *      Do a FETCH or MOVE in a cursor
1639  */
1640 static void
1641 _SPI_cursor_operation(Portal portal, bool forward, long count,
1642                                           DestReceiver *dest)
1643 {
1644         long            nfetched;
1645
1646         /* Check that the portal is valid */
1647         if (!PortalIsValid(portal))
1648                 elog(ERROR, "invalid portal in SPI cursor operation");
1649
1650         /* Push the SPI stack */
1651         if (_SPI_begin_call(true) < 0)
1652                 elog(ERROR, "SPI cursor operation called while not connected");
1653
1654         /* Reset the SPI result (note we deliberately don't touch lastoid) */
1655         SPI_processed = 0;
1656         SPI_tuptable = NULL;
1657         _SPI_current->processed = 0;
1658         _SPI_current->tuptable = NULL;
1659
1660         /* Run the cursor */
1661         nfetched = PortalRunFetch(portal,
1662                                                           forward ? FETCH_FORWARD : FETCH_BACKWARD,
1663                                                           count,
1664                                                           dest);
1665
1666         /*
1667          * Think not to combine this store with the preceding function call. If
1668          * the portal contains calls to functions that use SPI, then SPI_stack is
1669          * likely to move around while the portal runs.  When control returns,
1670          * _SPI_current will point to the correct stack entry... but the pointer
1671          * may be different than it was beforehand. So we must be sure to re-fetch
1672          * the pointer after the function call completes.
1673          */
1674         _SPI_current->processed = nfetched;
1675
1676         if (dest->mydest == DestSPI && _SPI_checktuples())
1677                 elog(ERROR, "consistency check on SPI tuple count failed");
1678
1679         /* Put the result into place for access by caller */
1680         SPI_processed = _SPI_current->processed;
1681         SPI_tuptable = _SPI_current->tuptable;
1682
1683         /* Pop the SPI stack */
1684         _SPI_end_call(true);
1685 }
1686
1687
1688 static MemoryContext
1689 _SPI_execmem(void)
1690 {
1691         return MemoryContextSwitchTo(_SPI_current->execCxt);
1692 }
1693
1694 static MemoryContext
1695 _SPI_procmem(void)
1696 {
1697         return MemoryContextSwitchTo(_SPI_current->procCxt);
1698 }
1699
1700 /*
1701  * _SPI_begin_call: begin a SPI operation within a connected procedure
1702  */
1703 static int
1704 _SPI_begin_call(bool execmem)
1705 {
1706         if (_SPI_curid + 1 != _SPI_connected)
1707                 return SPI_ERROR_UNCONNECTED;
1708         _SPI_curid++;
1709         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1710                 elog(ERROR, "SPI stack corrupted");
1711
1712         if (execmem)                            /* switch to the Executor memory context */
1713                 _SPI_execmem();
1714
1715         return 0;
1716 }
1717
1718 /*
1719  * _SPI_end_call: end a SPI operation within a connected procedure
1720  *
1721  * Note: this currently has no failure return cases, so callers don't check
1722  */
1723 static int
1724 _SPI_end_call(bool procmem)
1725 {
1726         /*
1727          * We're returning to procedure where _SPI_curid == _SPI_connected - 1
1728          */
1729         _SPI_curid--;
1730
1731         if (procmem)                            /* switch to the procedure memory context */
1732         {
1733                 _SPI_procmem();
1734                 /* and free Executor memory */
1735                 MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
1736         }
1737
1738         return 0;
1739 }
1740
1741 static bool
1742 _SPI_checktuples(void)
1743 {
1744         uint32          processed = _SPI_current->processed;
1745         SPITupleTable *tuptable = _SPI_current->tuptable;
1746         bool            failed = false;
1747
1748         if (tuptable == NULL)           /* spi_dest_startup was not called */
1749                 failed = true;
1750         else if (processed != (tuptable->alloced - tuptable->free))
1751                 failed = true;
1752
1753         return failed;
1754 }
1755
1756 static _SPI_plan *
1757 _SPI_copy_plan(_SPI_plan *plan, int location)
1758 {
1759         _SPI_plan  *newplan;
1760         MemoryContext oldcxt;
1761         MemoryContext plancxt;
1762         MemoryContext parentcxt;
1763
1764         /* Determine correct parent for the plan's memory context */
1765         if (location == _SPI_CPLAN_PROCXT)
1766                 parentcxt = _SPI_current->procCxt;
1767         else if (location == _SPI_CPLAN_TOPCXT)
1768                 parentcxt = TopMemoryContext;
1769         else
1770                 /* (this case not currently used) */
1771                 parentcxt = CurrentMemoryContext;
1772
1773         /*
1774          * Create a memory context for the plan.  We don't expect the plan to be
1775          * very large, so use smaller-than-default alloc parameters.
1776          */
1777         plancxt = AllocSetContextCreate(parentcxt,
1778                                                                         "SPI Plan",
1779                                                                         ALLOCSET_SMALL_MINSIZE,
1780                                                                         ALLOCSET_SMALL_INITSIZE,
1781                                                                         ALLOCSET_SMALL_MAXSIZE);
1782         oldcxt = MemoryContextSwitchTo(plancxt);
1783
1784         /* Copy the SPI plan into its own context */
1785         newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
1786         newplan->plancxt = plancxt;
1787         newplan->query = pstrdup(plan->query);
1788         newplan->qtlist = (List *) copyObject(plan->qtlist);
1789         newplan->ptlist = (List *) copyObject(plan->ptlist);
1790         newplan->nargs = plan->nargs;
1791         if (plan->nargs > 0)
1792         {
1793                 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
1794                 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
1795         }
1796         else
1797                 newplan->argtypes = NULL;
1798
1799         MemoryContextSwitchTo(oldcxt);
1800
1801         return newplan;
1802 }