]> granicus.if.org Git - postgresql/blob - src/backend/executor/spi.c
Update copyright for 2009.
[postgresql] / src / backend / executor / spi.c
1 /*-------------------------------------------------------------------------
2  *
3  * spi.c
4  *                              Server Programming Interface
5  *
6  * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.203 2009/01/01 17:23:42 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16
17 #include "access/printtup.h"
18 #include "access/sysattr.h"
19 #include "catalog/heap.h"
20 #include "commands/trigger.h"
21 #include "executor/spi_priv.h"
22 #include "utils/lsyscache.h"
23 #include "utils/memutils.h"
24 #include "utils/snapmgr.h"
25 #include "utils/typcache.h"
26
27
28 uint32          SPI_processed = 0;
29 Oid                     SPI_lastoid = InvalidOid;
30 SPITupleTable *SPI_tuptable = NULL;
31 int                     SPI_result;
32
33 static _SPI_connection *_SPI_stack = NULL;
34 static _SPI_connection *_SPI_current = NULL;
35 static int      _SPI_stack_depth = 0;           /* allocated size of _SPI_stack */
36 static int      _SPI_connected = -1;
37 static int      _SPI_curid = -1;
38
39 static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
40                                                                            Datum *Values, const char *Nulls,
41                                                                            bool read_only, int pflags);
42
43 static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan,
44                                                           ParamListInfo boundParams);
45
46 static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
47                                   Snapshot snapshot, Snapshot crosscheck_snapshot,
48                                   bool read_only, bool fire_triggers, long tcount);
49
50 static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
51                                         Datum *Values, const char *Nulls,
52                                         int pflags);
53
54 static int      _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount);
55
56 static void _SPI_error_callback(void *arg);
57
58 static void _SPI_cursor_operation(Portal portal,
59                                           FetchDirection direction, long count,
60                                           DestReceiver *dest);
61
62 static SPIPlanPtr _SPI_copy_plan(SPIPlanPtr plan, MemoryContext parentcxt);
63 static SPIPlanPtr _SPI_save_plan(SPIPlanPtr plan);
64
65 static int      _SPI_begin_call(bool execmem);
66 static int      _SPI_end_call(bool procmem);
67 static MemoryContext _SPI_execmem(void);
68 static MemoryContext _SPI_procmem(void);
69 static bool _SPI_checktuples(void);
70
71
72 /* =================== interface functions =================== */
73
74 int
75 SPI_connect(void)
76 {
77         int                     newdepth;
78
79         /*
80          * When procedure called by Executor _SPI_curid expected to be equal to
81          * _SPI_connected
82          */
83         if (_SPI_curid != _SPI_connected)
84                 return SPI_ERROR_CONNECT;
85
86         if (_SPI_stack == NULL)
87         {
88                 if (_SPI_connected != -1 || _SPI_stack_depth != 0)
89                         elog(ERROR, "SPI stack corrupted");
90                 newdepth = 16;
91                 _SPI_stack = (_SPI_connection *)
92                         MemoryContextAlloc(TopTransactionContext,
93                                                            newdepth * sizeof(_SPI_connection));
94                 _SPI_stack_depth = newdepth;
95         }
96         else
97         {
98                 if (_SPI_stack_depth <= 0 || _SPI_stack_depth <= _SPI_connected)
99                         elog(ERROR, "SPI stack corrupted");
100                 if (_SPI_stack_depth == _SPI_connected + 1)
101                 {
102                         newdepth = _SPI_stack_depth * 2;
103                         _SPI_stack = (_SPI_connection *)
104                                 repalloc(_SPI_stack,
105                                                  newdepth * sizeof(_SPI_connection));
106                         _SPI_stack_depth = newdepth;
107                 }
108         }
109
110         /*
111          * We're entering procedure where _SPI_curid == _SPI_connected - 1
112          */
113         _SPI_connected++;
114         Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth);
115
116         _SPI_current = &(_SPI_stack[_SPI_connected]);
117         _SPI_current->processed = 0;
118         _SPI_current->lastoid = InvalidOid;
119         _SPI_current->tuptable = NULL;
120         _SPI_current->procCxt = NULL;           /* in case we fail to create 'em */
121         _SPI_current->execCxt = NULL;
122         _SPI_current->connectSubid = GetCurrentSubTransactionId();
123
124         /*
125          * Create memory contexts for this procedure
126          *
127          * XXX it would be better to use PortalContext as the parent context, but
128          * we may not be inside a portal (consider deferred-trigger execution).
129          * Perhaps CurTransactionContext would do?      For now it doesn't matter
130          * because we clean up explicitly in AtEOSubXact_SPI().
131          */
132         _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
133                                                                                                   "SPI Proc",
134                                                                                                   ALLOCSET_DEFAULT_MINSIZE,
135                                                                                                   ALLOCSET_DEFAULT_INITSIZE,
136                                                                                                   ALLOCSET_DEFAULT_MAXSIZE);
137         _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
138                                                                                                   "SPI Exec",
139                                                                                                   ALLOCSET_DEFAULT_MINSIZE,
140                                                                                                   ALLOCSET_DEFAULT_INITSIZE,
141                                                                                                   ALLOCSET_DEFAULT_MAXSIZE);
142         /* ... and switch to procedure's context */
143         _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
144
145         return SPI_OK_CONNECT;
146 }
147
148 int
149 SPI_finish(void)
150 {
151         int                     res;
152
153         res = _SPI_begin_call(false);           /* live in procedure memory */
154         if (res < 0)
155                 return res;
156
157         /* Restore memory context as it was before procedure call */
158         MemoryContextSwitchTo(_SPI_current->savedcxt);
159
160         /* Release memory used in procedure call */
161         MemoryContextDelete(_SPI_current->execCxt);
162         _SPI_current->execCxt = NULL;
163         MemoryContextDelete(_SPI_current->procCxt);
164         _SPI_current->procCxt = NULL;
165
166         /*
167          * Reset result variables, especially SPI_tuptable which is probably
168          * pointing at a just-deleted tuptable
169          */
170         SPI_processed = 0;
171         SPI_lastoid = InvalidOid;
172         SPI_tuptable = NULL;
173
174         /*
175          * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are closing
176          * connection to SPI and returning to upper Executor and so _SPI_connected
177          * must be equal to _SPI_curid.
178          */
179         _SPI_connected--;
180         _SPI_curid--;
181         if (_SPI_connected == -1)
182                 _SPI_current = NULL;
183         else
184                 _SPI_current = &(_SPI_stack[_SPI_connected]);
185
186         return SPI_OK_FINISH;
187 }
188
189 /*
190  * Clean up SPI state at transaction commit or abort.
191  */
192 void
193 AtEOXact_SPI(bool isCommit)
194 {
195         /*
196          * Note that memory contexts belonging to SPI stack entries will be freed
197          * automatically, so we can ignore them here.  We just need to restore our
198          * static variables to initial state.
199          */
200         if (isCommit && _SPI_connected != -1)
201                 ereport(WARNING,
202                                 (errcode(ERRCODE_WARNING),
203                                  errmsg("transaction left non-empty SPI stack"),
204                                  errhint("Check for missing \"SPI_finish\" calls.")));
205
206         _SPI_current = _SPI_stack = NULL;
207         _SPI_stack_depth = 0;
208         _SPI_connected = _SPI_curid = -1;
209         SPI_processed = 0;
210         SPI_lastoid = InvalidOid;
211         SPI_tuptable = NULL;
212 }
213
214 /*
215  * Clean up SPI state at subtransaction commit or abort.
216  *
217  * During commit, there shouldn't be any unclosed entries remaining from
218  * the current subtransaction; we emit a warning if any are found.
219  */
220 void
221 AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
222 {
223         bool            found = false;
224
225         while (_SPI_connected >= 0)
226         {
227                 _SPI_connection *connection = &(_SPI_stack[_SPI_connected]);
228
229                 if (connection->connectSubid != mySubid)
230                         break;                          /* couldn't be any underneath it either */
231
232                 found = true;
233
234                 /*
235                  * Release procedure memory explicitly (see note in SPI_connect)
236                  */
237                 if (connection->execCxt)
238                 {
239                         MemoryContextDelete(connection->execCxt);
240                         connection->execCxt = NULL;
241                 }
242                 if (connection->procCxt)
243                 {
244                         MemoryContextDelete(connection->procCxt);
245                         connection->procCxt = NULL;
246                 }
247
248                 /*
249                  * Pop the stack entry and reset global variables.      Unlike
250                  * SPI_finish(), we don't risk switching to memory contexts that might
251                  * be already gone.
252                  */
253                 _SPI_connected--;
254                 _SPI_curid = _SPI_connected;
255                 if (_SPI_connected == -1)
256                         _SPI_current = NULL;
257                 else
258                         _SPI_current = &(_SPI_stack[_SPI_connected]);
259                 SPI_processed = 0;
260                 SPI_lastoid = InvalidOid;
261                 SPI_tuptable = NULL;
262         }
263
264         if (found && isCommit)
265                 ereport(WARNING,
266                                 (errcode(ERRCODE_WARNING),
267                                  errmsg("subtransaction left non-empty SPI stack"),
268                                  errhint("Check for missing \"SPI_finish\" calls.")));
269
270         /*
271          * If we are aborting a subtransaction and there is an open SPI context
272          * surrounding the subxact, clean up to prevent memory leakage.
273          */
274         if (_SPI_current && !isCommit)
275         {
276                 /* free Executor memory the same as _SPI_end_call would do */
277                 MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
278                 /* throw away any partially created tuple-table */
279                 SPI_freetuptable(_SPI_current->tuptable);
280                 _SPI_current->tuptable = NULL;
281         }
282 }
283
284
285 /* Pushes SPI stack to allow recursive SPI calls */
286 void
287 SPI_push(void)
288 {
289         _SPI_curid++;
290 }
291
292 /* Pops SPI stack to allow recursive SPI calls */
293 void
294 SPI_pop(void)
295 {
296         _SPI_curid--;
297 }
298
299 /* Restore state of SPI stack after aborting a subtransaction */
300 void
301 SPI_restore_connection(void)
302 {
303         Assert(_SPI_connected >= 0);
304         _SPI_curid = _SPI_connected - 1;
305 }
306
307 /* Parse, plan, and execute a query string */
308 int
309 SPI_execute(const char *src, bool read_only, long tcount)
310 {
311         _SPI_plan       plan;
312         int                     res;
313
314         if (src == NULL || tcount < 0)
315                 return SPI_ERROR_ARGUMENT;
316
317         res = _SPI_begin_call(true);
318         if (res < 0)
319                 return res;
320
321         memset(&plan, 0, sizeof(_SPI_plan));
322         plan.magic = _SPI_PLAN_MAGIC;
323         plan.cursor_options = 0;
324
325         _SPI_prepare_plan(src, &plan, NULL);
326
327         res = _SPI_execute_plan(&plan, NULL,
328                                                         InvalidSnapshot, InvalidSnapshot,
329                                                         read_only, true, tcount);
330
331         _SPI_end_call(true);
332         return res;
333 }
334
335 /* Obsolete version of SPI_execute */
336 int
337 SPI_exec(const char *src, long tcount)
338 {
339         return SPI_execute(src, false, tcount);
340 }
341
342 /* Execute a previously prepared plan */
343 int
344 SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
345                                  bool read_only, long tcount)
346 {
347         int                     res;
348
349         if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
350                 return SPI_ERROR_ARGUMENT;
351
352         if (plan->nargs > 0 && Values == NULL)
353                 return SPI_ERROR_PARAM;
354
355         res = _SPI_begin_call(true);
356         if (res < 0)
357                 return res;
358
359         res = _SPI_execute_plan(plan,
360                                                         _SPI_convert_params(plan->nargs, plan->argtypes,
361                                                                                                 Values, Nulls,
362                                                                                                 0),
363                                                         InvalidSnapshot, InvalidSnapshot,
364                                                         read_only, true, tcount);
365
366         _SPI_end_call(true);
367         return res;
368 }
369
370 /* Obsolete version of SPI_execute_plan */
371 int
372 SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
373 {
374         return SPI_execute_plan(plan, Values, Nulls, false, tcount);
375 }
376
377 /*
378  * SPI_execute_snapshot -- identical to SPI_execute_plan, except that we allow
379  * the caller to specify exactly which snapshots to use, which will be
380  * registered here.  Also, the caller may specify that AFTER triggers should be
381  * queued as part of the outer query rather than being fired immediately at the
382  * end of the command.
383  *
384  * This is currently not documented in spi.sgml because it is only intended
385  * for use by RI triggers.
386  *
387  * Passing snapshot == InvalidSnapshot will select the normal behavior of
388  * fetching a new snapshot for each query.
389  */
390 int
391 SPI_execute_snapshot(SPIPlanPtr plan,
392                                          Datum *Values, const char *Nulls,
393                                          Snapshot snapshot, Snapshot crosscheck_snapshot,
394                                          bool read_only, bool fire_triggers, long tcount)
395 {
396         int                     res;
397
398         if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
399                 return SPI_ERROR_ARGUMENT;
400
401         if (plan->nargs > 0 && Values == NULL)
402                 return SPI_ERROR_PARAM;
403
404         res = _SPI_begin_call(true);
405         if (res < 0)
406                 return res;
407
408         res = _SPI_execute_plan(plan,
409                                                         _SPI_convert_params(plan->nargs, plan->argtypes,
410                                                                                                 Values, Nulls,
411                                                                                                 0),
412                                                         snapshot, crosscheck_snapshot,
413                                                         read_only, fire_triggers, tcount);
414
415         _SPI_end_call(true);
416         return res;
417 }
418
419 /*
420  * SPI_execute_with_args -- plan and execute a query with supplied arguments
421  *
422  * This is functionally comparable to SPI_prepare followed by
423  * SPI_execute_plan, except that since we know the plan will be used only
424  * once, we can tell the planner to rely on the parameter values as constants.
425  * This eliminates potential performance disadvantages compared to
426  * inserting the parameter values directly into the query text.
427  */
428 int
429 SPI_execute_with_args(const char *src,
430                                           int nargs, Oid *argtypes,
431                                           Datum *Values, const char *Nulls,
432                                           bool read_only, long tcount)
433 {
434         int                     res;
435         _SPI_plan       plan;
436         ParamListInfo paramLI;
437
438         if (src == NULL || nargs < 0 || tcount < 0)
439                 return SPI_ERROR_ARGUMENT;
440
441         if (nargs > 0 && (argtypes == NULL || Values == NULL))
442                 return SPI_ERROR_PARAM;
443
444         res = _SPI_begin_call(true);
445         if (res < 0)
446                 return res;
447
448         memset(&plan, 0, sizeof(_SPI_plan));
449         plan.magic = _SPI_PLAN_MAGIC;
450         plan.cursor_options = 0;
451         plan.nargs = nargs;
452         plan.argtypes = argtypes;
453
454         paramLI = _SPI_convert_params(nargs, argtypes,
455                                                                   Values, Nulls,
456                                                                   PARAM_FLAG_CONST);
457
458         _SPI_prepare_plan(src, &plan, paramLI);
459
460         /* We don't need to copy the plan since it will be thrown away anyway */
461
462         res = _SPI_execute_plan(&plan, paramLI,
463                                                         InvalidSnapshot, InvalidSnapshot,
464                                                         read_only, true, tcount);
465
466         _SPI_end_call(true);
467         return res;
468 }
469
470 SPIPlanPtr
471 SPI_prepare(const char *src, int nargs, Oid *argtypes)
472 {
473         return SPI_prepare_cursor(src, nargs, argtypes, 0);
474 }
475
476 SPIPlanPtr
477 SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
478                                    int cursorOptions)
479 {
480         _SPI_plan       plan;
481         SPIPlanPtr      result;
482
483         if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
484         {
485                 SPI_result = SPI_ERROR_ARGUMENT;
486                 return NULL;
487         }
488
489         SPI_result = _SPI_begin_call(true);
490         if (SPI_result < 0)
491                 return NULL;
492
493         memset(&plan, 0, sizeof(_SPI_plan));
494         plan.magic = _SPI_PLAN_MAGIC;
495         plan.cursor_options = cursorOptions;
496         plan.nargs = nargs;
497         plan.argtypes = argtypes;
498
499         _SPI_prepare_plan(src, &plan, NULL);
500
501         /* copy plan to procedure context */
502         result = _SPI_copy_plan(&plan, _SPI_current->procCxt);
503
504         _SPI_end_call(true);
505
506         return result;
507 }
508
509 SPIPlanPtr
510 SPI_saveplan(SPIPlanPtr plan)
511 {
512         SPIPlanPtr      newplan;
513
514         /* We don't currently support copying an already-saved plan */
515         if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || plan->saved)
516         {
517                 SPI_result = SPI_ERROR_ARGUMENT;
518                 return NULL;
519         }
520
521         SPI_result = _SPI_begin_call(false);            /* don't change context */
522         if (SPI_result < 0)
523                 return NULL;
524
525         newplan = _SPI_save_plan(plan);
526
527         _SPI_curid--;
528         SPI_result = 0;
529
530         return newplan;
531 }
532
533 int
534 SPI_freeplan(SPIPlanPtr plan)
535 {
536         if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
537                 return SPI_ERROR_ARGUMENT;
538
539         /* If plancache.c owns the plancache entries, we must release them */
540         if (plan->saved)
541         {
542                 ListCell   *lc;
543
544                 foreach(lc, plan->plancache_list)
545                 {
546                         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
547
548                         DropCachedPlan(plansource);
549                 }
550         }
551
552         /* Now get rid of the _SPI_plan and subsidiary data in its plancxt */
553         MemoryContextDelete(plan->plancxt);
554
555         return 0;
556 }
557
558 HeapTuple
559 SPI_copytuple(HeapTuple tuple)
560 {
561         MemoryContext oldcxt = NULL;
562         HeapTuple       ctuple;
563
564         if (tuple == NULL)
565         {
566                 SPI_result = SPI_ERROR_ARGUMENT;
567                 return NULL;
568         }
569
570         if (_SPI_curid + 1 == _SPI_connected)           /* connected */
571         {
572                 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
573                         elog(ERROR, "SPI stack corrupted");
574                 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
575         }
576
577         ctuple = heap_copytuple(tuple);
578
579         if (oldcxt)
580                 MemoryContextSwitchTo(oldcxt);
581
582         return ctuple;
583 }
584
585 HeapTupleHeader
586 SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
587 {
588         MemoryContext oldcxt = NULL;
589         HeapTupleHeader dtup;
590
591         if (tuple == NULL || tupdesc == NULL)
592         {
593                 SPI_result = SPI_ERROR_ARGUMENT;
594                 return NULL;
595         }
596
597         /* For RECORD results, make sure a typmod has been assigned */
598         if (tupdesc->tdtypeid == RECORDOID &&
599                 tupdesc->tdtypmod < 0)
600                 assign_record_type_typmod(tupdesc);
601
602         if (_SPI_curid + 1 == _SPI_connected)           /* connected */
603         {
604                 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
605                         elog(ERROR, "SPI stack corrupted");
606                 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
607         }
608
609         dtup = (HeapTupleHeader) palloc(tuple->t_len);
610         memcpy((char *) dtup, (char *) tuple->t_data, tuple->t_len);
611
612         HeapTupleHeaderSetDatumLength(dtup, tuple->t_len);
613         HeapTupleHeaderSetTypeId(dtup, tupdesc->tdtypeid);
614         HeapTupleHeaderSetTypMod(dtup, tupdesc->tdtypmod);
615
616         if (oldcxt)
617                 MemoryContextSwitchTo(oldcxt);
618
619         return dtup;
620 }
621
622 HeapTuple
623 SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
624                                 Datum *Values, const char *Nulls)
625 {
626         MemoryContext oldcxt = NULL;
627         HeapTuple       mtuple;
628         int                     numberOfAttributes;
629         Datum      *v;
630         bool       *n;
631         int                     i;
632
633         if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
634         {
635                 SPI_result = SPI_ERROR_ARGUMENT;
636                 return NULL;
637         }
638
639         if (_SPI_curid + 1 == _SPI_connected)           /* connected */
640         {
641                 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
642                         elog(ERROR, "SPI stack corrupted");
643                 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
644         }
645         SPI_result = 0;
646         numberOfAttributes = rel->rd_att->natts;
647         v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
648         n = (bool *) palloc(numberOfAttributes * sizeof(bool));
649
650         /* fetch old values and nulls */
651         heap_deform_tuple(tuple, rel->rd_att, v, n);
652
653         /* replace values and nulls */
654         for (i = 0; i < natts; i++)
655         {
656                 if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
657                         break;
658                 v[attnum[i] - 1] = Values[i];
659                 n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? true : false;
660         }
661
662         if (i == natts)                         /* no errors in *attnum */
663         {
664                 mtuple = heap_form_tuple(rel->rd_att, v, n);
665
666                 /*
667                  * copy the identification info of the old tuple: t_ctid, t_self, and
668                  * OID (if any)
669                  */
670                 mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
671                 mtuple->t_self = tuple->t_self;
672                 mtuple->t_tableOid = tuple->t_tableOid;
673                 if (rel->rd_att->tdhasoid)
674                         HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
675         }
676         else
677         {
678                 mtuple = NULL;
679                 SPI_result = SPI_ERROR_NOATTRIBUTE;
680         }
681
682         pfree(v);
683         pfree(n);
684
685         if (oldcxt)
686                 MemoryContextSwitchTo(oldcxt);
687
688         return mtuple;
689 }
690
691 int
692 SPI_fnumber(TupleDesc tupdesc, const char *fname)
693 {
694         int                     res;
695         Form_pg_attribute sysatt;
696
697         for (res = 0; res < tupdesc->natts; res++)
698         {
699                 if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0)
700                         return res + 1;
701         }
702
703         sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ );
704         if (sysatt != NULL)
705                 return sysatt->attnum;
706
707         /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
708         return SPI_ERROR_NOATTRIBUTE;
709 }
710
711 char *
712 SPI_fname(TupleDesc tupdesc, int fnumber)
713 {
714         Form_pg_attribute att;
715
716         SPI_result = 0;
717
718         if (fnumber > tupdesc->natts || fnumber == 0 ||
719                 fnumber <= FirstLowInvalidHeapAttributeNumber)
720         {
721                 SPI_result = SPI_ERROR_NOATTRIBUTE;
722                 return NULL;
723         }
724
725         if (fnumber > 0)
726                 att = tupdesc->attrs[fnumber - 1];
727         else
728                 att = SystemAttributeDefinition(fnumber, true);
729
730         return pstrdup(NameStr(att->attname));
731 }
732
733 char *
734 SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
735 {
736         char       *result;
737         Datum           origval,
738                                 val;
739         bool            isnull;
740         Oid                     typoid,
741                                 foutoid;
742         bool            typisvarlena;
743
744         SPI_result = 0;
745
746         if (fnumber > tupdesc->natts || fnumber == 0 ||
747                 fnumber <= FirstLowInvalidHeapAttributeNumber)
748         {
749                 SPI_result = SPI_ERROR_NOATTRIBUTE;
750                 return NULL;
751         }
752
753         origval = heap_getattr(tuple, fnumber, tupdesc, &isnull);
754         if (isnull)
755                 return NULL;
756
757         if (fnumber > 0)
758                 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
759         else
760                 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
761
762         getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
763
764         /*
765          * If we have a toasted datum, forcibly detoast it here to avoid memory
766          * leakage inside the type's output routine.
767          */
768         if (typisvarlena)
769                 val = PointerGetDatum(PG_DETOAST_DATUM(origval));
770         else
771                 val = origval;
772
773         result = OidOutputFunctionCall(foutoid, val);
774
775         /* Clean up detoasted copy, if any */
776         if (val != origval)
777                 pfree(DatumGetPointer(val));
778
779         return result;
780 }
781
782 Datum
783 SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
784 {
785         SPI_result = 0;
786
787         if (fnumber > tupdesc->natts || fnumber == 0 ||
788                 fnumber <= FirstLowInvalidHeapAttributeNumber)
789         {
790                 SPI_result = SPI_ERROR_NOATTRIBUTE;
791                 *isnull = true;
792                 return (Datum) NULL;
793         }
794
795         return heap_getattr(tuple, fnumber, tupdesc, isnull);
796 }
797
798 char *
799 SPI_gettype(TupleDesc tupdesc, int fnumber)
800 {
801         Oid                     typoid;
802         HeapTuple       typeTuple;
803         char       *result;
804
805         SPI_result = 0;
806
807         if (fnumber > tupdesc->natts || fnumber == 0 ||
808                 fnumber <= FirstLowInvalidHeapAttributeNumber)
809         {
810                 SPI_result = SPI_ERROR_NOATTRIBUTE;
811                 return NULL;
812         }
813
814         if (fnumber > 0)
815                 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
816         else
817                 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
818
819         typeTuple = SearchSysCache(TYPEOID,
820                                                            ObjectIdGetDatum(typoid),
821                                                            0, 0, 0);
822
823         if (!HeapTupleIsValid(typeTuple))
824         {
825                 SPI_result = SPI_ERROR_TYPUNKNOWN;
826                 return NULL;
827         }
828
829         result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
830         ReleaseSysCache(typeTuple);
831         return result;
832 }
833
834 Oid
835 SPI_gettypeid(TupleDesc tupdesc, int fnumber)
836 {
837         SPI_result = 0;
838
839         if (fnumber > tupdesc->natts || fnumber == 0 ||
840                 fnumber <= FirstLowInvalidHeapAttributeNumber)
841         {
842                 SPI_result = SPI_ERROR_NOATTRIBUTE;
843                 return InvalidOid;
844         }
845
846         if (fnumber > 0)
847                 return tupdesc->attrs[fnumber - 1]->atttypid;
848         else
849                 return (SystemAttributeDefinition(fnumber, true))->atttypid;
850 }
851
852 char *
853 SPI_getrelname(Relation rel)
854 {
855         return pstrdup(RelationGetRelationName(rel));
856 }
857
858 char *
859 SPI_getnspname(Relation rel)
860 {
861         return get_namespace_name(RelationGetNamespace(rel));
862 }
863
864 void *
865 SPI_palloc(Size size)
866 {
867         MemoryContext oldcxt = NULL;
868         void       *pointer;
869
870         if (_SPI_curid + 1 == _SPI_connected)           /* connected */
871         {
872                 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
873                         elog(ERROR, "SPI stack corrupted");
874                 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
875         }
876
877         pointer = palloc(size);
878
879         if (oldcxt)
880                 MemoryContextSwitchTo(oldcxt);
881
882         return pointer;
883 }
884
885 void *
886 SPI_repalloc(void *pointer, Size size)
887 {
888         /* No longer need to worry which context chunk was in... */
889         return repalloc(pointer, size);
890 }
891
892 void
893 SPI_pfree(void *pointer)
894 {
895         /* No longer need to worry which context chunk was in... */
896         pfree(pointer);
897 }
898
899 void
900 SPI_freetuple(HeapTuple tuple)
901 {
902         /* No longer need to worry which context tuple was in... */
903         heap_freetuple(tuple);
904 }
905
906 void
907 SPI_freetuptable(SPITupleTable *tuptable)
908 {
909         if (tuptable != NULL)
910                 MemoryContextDelete(tuptable->tuptabcxt);
911 }
912
913
914 /*
915  * SPI_cursor_open()
916  *
917  *      Open a prepared SPI plan as a portal
918  */
919 Portal
920 SPI_cursor_open(const char *name, SPIPlanPtr plan,
921                                 Datum *Values, const char *Nulls,
922                                 bool read_only)
923 {
924         return SPI_cursor_open_internal(name, plan, Values, Nulls,
925                                                                         read_only, 0);
926 }
927
928
929 /*
930  * SPI_cursor_open_with_args()
931  *
932  * Parse and plan a query and open it as a portal.  Like SPI_execute_with_args,
933  * we can tell the planner to rely on the parameter values as constants,
934  * because the plan will only be used once.
935  */
936 Portal
937 SPI_cursor_open_with_args(const char *name,
938                                                   const char *src,
939                                                   int nargs, Oid *argtypes,
940                                                   Datum *Values, const char *Nulls,
941                                                   bool read_only, int cursorOptions)
942 {
943         Portal          result;
944         _SPI_plan       plan;
945         ParamListInfo paramLI;
946
947         if (src == NULL || nargs < 0)
948                 elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments");
949
950         if (nargs > 0 && (argtypes == NULL || Values == NULL))
951                 elog(ERROR, "SPI_cursor_open_with_args called with missing parameters");
952
953         SPI_result = _SPI_begin_call(true);
954         if (SPI_result < 0)
955                 elog(ERROR, "SPI_cursor_open_with_args called while not connected");
956
957         memset(&plan, 0, sizeof(_SPI_plan));
958         plan.magic = _SPI_PLAN_MAGIC;
959         plan.cursor_options = cursorOptions;
960         plan.nargs = nargs;
961         plan.argtypes = argtypes;
962
963         paramLI = _SPI_convert_params(nargs, argtypes,
964                                                                   Values, Nulls,
965                                                                   PARAM_FLAG_CONST);
966
967         _SPI_prepare_plan(src, &plan, paramLI);
968
969         /* We needn't copy the plan; SPI_cursor_open_internal will do so */
970
971         /* Adjust stack so that SPI_cursor_open_internal doesn't complain */
972         _SPI_curid--;
973
974         /* SPI_cursor_open_internal must be called in procedure memory context */
975         _SPI_procmem();
976
977         result = SPI_cursor_open_internal(name, &plan, Values, Nulls,
978                                                                           read_only, PARAM_FLAG_CONST);
979
980         /* And clean up */
981         _SPI_curid++;
982         _SPI_end_call(true);
983
984         return result;
985 }
986
987
988 /*
989  * SPI_cursor_open_internal()
990  *
991  *      Common code for SPI_cursor_open and SPI_cursor_open_with_args
992  */
993 static Portal
994 SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
995                                                  Datum *Values, const char *Nulls,
996                                                  bool read_only, int pflags)
997 {
998         CachedPlanSource *plansource;
999         CachedPlan *cplan;
1000         List       *stmt_list;
1001         char       *query_string;
1002         ParamListInfo paramLI;
1003         Snapshot        snapshot;
1004         MemoryContext oldcontext;
1005         Portal          portal;
1006         int                     k;
1007
1008         /*
1009          * Check that the plan is something the Portal code will special-case as
1010          * returning one tupleset.
1011          */
1012         if (!SPI_is_cursor_plan(plan))
1013         {
1014                 /* try to give a good error message */
1015                 if (list_length(plan->plancache_list) != 1)
1016                         ereport(ERROR,
1017                                         (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
1018                                          errmsg("cannot open multi-query plan as cursor")));
1019                 plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1020                 ereport(ERROR,
1021                                 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
1022                 /* translator: %s is name of a SQL command, eg INSERT */
1023                                  errmsg("cannot open %s query as cursor",
1024                                                 plansource->commandTag)));
1025         }
1026
1027         Assert(list_length(plan->plancache_list) == 1);
1028         plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1029
1030         /* Push the SPI stack */
1031         if (_SPI_begin_call(false) < 0)
1032                 elog(ERROR, "SPI_cursor_open called while not connected");
1033
1034         /* Reset SPI result (note we deliberately don't touch lastoid) */
1035         SPI_processed = 0;
1036         SPI_tuptable = NULL;
1037         _SPI_current->processed = 0;
1038         _SPI_current->tuptable = NULL;
1039
1040         /* Create the portal */
1041         if (name == NULL || name[0] == '\0')
1042         {
1043                 /* Use a random nonconflicting name */
1044                 portal = CreateNewPortal();
1045         }
1046         else
1047         {
1048                 /* In this path, error if portal of same name already exists */
1049                 portal = CreatePortal(name, false, false);
1050         }
1051
1052         /*
1053          * Prepare to copy stuff into the portal's memory context.  We do all this
1054          * copying first, because it could possibly fail (out-of-memory) and we
1055          * don't want a failure to occur between RevalidateCachedPlan and
1056          * PortalDefineQuery; that would result in leaking our plancache refcount.
1057          */
1058         oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
1059
1060         /* Copy the plan's query string into the portal */
1061         query_string = pstrdup(plansource->query_string);
1062
1063         /* If the plan has parameters, copy them into the portal */
1064         if (plan->nargs > 0)
1065         {
1066                 /* sizeof(ParamListInfoData) includes the first array element */
1067                 paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
1068                                                                  (plan->nargs - 1) *sizeof(ParamExternData));
1069                 paramLI->numParams = plan->nargs;
1070
1071                 for (k = 0; k < plan->nargs; k++)
1072                 {
1073                         ParamExternData *prm = &paramLI->params[k];
1074
1075                         prm->ptype = plan->argtypes[k];
1076                         prm->pflags = pflags;
1077                         prm->isnull = (Nulls && Nulls[k] == 'n');
1078                         if (prm->isnull)
1079                         {
1080                                 /* nulls just copy */
1081                                 prm->value = Values[k];
1082                         }
1083                         else
1084                         {
1085                                 /* pass-by-ref values must be copied into portal context */
1086                                 int16           paramTypLen;
1087                                 bool            paramTypByVal;
1088
1089                                 get_typlenbyval(prm->ptype, &paramTypLen, &paramTypByVal);
1090                                 prm->value = datumCopy(Values[k],
1091                                                                            paramTypByVal, paramTypLen);
1092                         }
1093                 }
1094         }
1095         else
1096                 paramLI = NULL;
1097
1098         MemoryContextSwitchTo(oldcontext);
1099
1100         if (plan->saved)
1101         {
1102                 /* Replan if needed, and increment plan refcount for portal */
1103                 cplan = RevalidateCachedPlan(plansource, false);
1104                 stmt_list = cplan->stmt_list;
1105         }
1106         else
1107         {
1108                 /* No replan, but copy the plan into the portal's context */
1109                 oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
1110                 stmt_list = copyObject(plansource->plan->stmt_list);
1111                 MemoryContextSwitchTo(oldcontext);
1112                 cplan = NULL;                   /* portal shouldn't depend on cplan */
1113         }
1114
1115         /*
1116          * Set up the portal.
1117          */
1118         PortalDefineQuery(portal,
1119                                           NULL,         /* no statement name */
1120                                           query_string,
1121                                           plansource->commandTag,
1122                                           stmt_list,
1123                                           cplan);
1124
1125         /*
1126          * Set up options for portal.  Default SCROLL type is chosen the same way
1127          * as PerformCursorOpen does it.
1128          */
1129         portal->cursorOptions = plan->cursor_options;
1130         if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
1131         {
1132                 if (list_length(stmt_list) == 1 &&
1133                         IsA((Node *) linitial(stmt_list), PlannedStmt) &&
1134                         ((PlannedStmt *) linitial(stmt_list))->rowMarks == NIL &&
1135                         ExecSupportsBackwardScan(((PlannedStmt *) linitial(stmt_list))->planTree))
1136                         portal->cursorOptions |= CURSOR_OPT_SCROLL;
1137                 else
1138                         portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
1139         }
1140
1141         /*
1142          * Disallow SCROLL with SELECT FOR UPDATE.      This is not redundant with the
1143          * check in transformDeclareCursorStmt because the cursor options might
1144          * not have come through there.
1145          */
1146         if (portal->cursorOptions & CURSOR_OPT_SCROLL)
1147         {
1148                 if (list_length(stmt_list) == 1 &&
1149                         IsA((Node *) linitial(stmt_list), PlannedStmt) &&
1150                         ((PlannedStmt *) linitial(stmt_list))->rowMarks != NIL)
1151                         ereport(ERROR,
1152                                         (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1153                                          errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"),
1154                                          errdetail("Scrollable cursors must be READ ONLY.")));
1155         }
1156
1157         /*
1158          * If told to be read-only, we'd better check for read-only queries. This
1159          * can't be done earlier because we need to look at the finished, planned
1160          * queries.  (In particular, we don't want to do it between
1161          * RevalidateCachedPlan and PortalDefineQuery, because throwing an error
1162          * between those steps would result in leaking our plancache refcount.)
1163          */
1164         if (read_only)
1165         {
1166                 ListCell   *lc;
1167
1168                 foreach(lc, stmt_list)
1169                 {
1170                         Node       *pstmt = (Node *) lfirst(lc);
1171
1172                         if (!CommandIsReadOnly(pstmt))
1173                                 ereport(ERROR,
1174                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1175                                 /* translator: %s is a SQL statement name */
1176                                            errmsg("%s is not allowed in a non-volatile function",
1177                                                           CreateCommandTag(pstmt))));
1178                 }
1179         }
1180
1181         /*
1182          * Set up the snapshot to use.  (PortalStart will do PushActiveSnapshot, so
1183          * we skip that here.)
1184          */
1185         if (read_only)
1186                 snapshot = GetActiveSnapshot();
1187         else
1188         {
1189                 CommandCounterIncrement();
1190                 snapshot = GetTransactionSnapshot();
1191         }
1192
1193         /*
1194          * Start portal execution.
1195          */
1196         PortalStart(portal, paramLI, snapshot);
1197
1198         Assert(portal->strategy != PORTAL_MULTI_QUERY);
1199
1200         /* Pop the SPI stack */
1201         _SPI_end_call(false);
1202
1203         /* Return the created portal */
1204         return portal;
1205 }
1206
1207
1208 /*
1209  * SPI_cursor_find()
1210  *
1211  *      Find the portal of an existing open cursor
1212  */
1213 Portal
1214 SPI_cursor_find(const char *name)
1215 {
1216         return GetPortalByName(name);
1217 }
1218
1219
1220 /*
1221  * SPI_cursor_fetch()
1222  *
1223  *      Fetch rows in a cursor
1224  */
1225 void
1226 SPI_cursor_fetch(Portal portal, bool forward, long count)
1227 {
1228         _SPI_cursor_operation(portal,
1229                                                   forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1230                                                   CreateDestReceiver(DestSPI));
1231         /* we know that the DestSPI receiver doesn't need a destroy call */
1232 }
1233
1234
1235 /*
1236  * SPI_cursor_move()
1237  *
1238  *      Move in a cursor
1239  */
1240 void
1241 SPI_cursor_move(Portal portal, bool forward, long count)
1242 {
1243         _SPI_cursor_operation(portal,
1244                                                   forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1245                                                   None_Receiver);
1246 }
1247
1248
1249 /*
1250  * SPI_scroll_cursor_fetch()
1251  *
1252  *      Fetch rows in a scrollable cursor
1253  */
1254 void
1255 SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count)
1256 {
1257         _SPI_cursor_operation(portal,
1258                                                   direction, count,
1259                                                   CreateDestReceiver(DestSPI));
1260         /* we know that the DestSPI receiver doesn't need a destroy call */
1261 }
1262
1263
1264 /*
1265  * SPI_scroll_cursor_move()
1266  *
1267  *      Move in a scrollable cursor
1268  */
1269 void
1270 SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count)
1271 {
1272         _SPI_cursor_operation(portal, direction, count, None_Receiver);
1273 }
1274
1275
1276 /*
1277  * SPI_cursor_close()
1278  *
1279  *      Close a cursor
1280  */
1281 void
1282 SPI_cursor_close(Portal portal)
1283 {
1284         if (!PortalIsValid(portal))
1285                 elog(ERROR, "invalid portal in SPI cursor operation");
1286
1287         PortalDrop(portal, false);
1288 }
1289
1290 /*
1291  * Returns the Oid representing the type id for argument at argIndex. First
1292  * parameter is at index zero.
1293  */
1294 Oid
1295 SPI_getargtypeid(SPIPlanPtr plan, int argIndex)
1296 {
1297         if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
1298                 argIndex < 0 || argIndex >= plan->nargs)
1299         {
1300                 SPI_result = SPI_ERROR_ARGUMENT;
1301                 return InvalidOid;
1302         }
1303         return plan->argtypes[argIndex];
1304 }
1305
1306 /*
1307  * Returns the number of arguments for the prepared plan.
1308  */
1309 int
1310 SPI_getargcount(SPIPlanPtr plan)
1311 {
1312         if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1313         {
1314                 SPI_result = SPI_ERROR_ARGUMENT;
1315                 return -1;
1316         }
1317         return plan->nargs;
1318 }
1319
1320 /*
1321  * Returns true if the plan contains exactly one command
1322  * and that command returns tuples to the caller (eg, SELECT or
1323  * INSERT ... RETURNING, but not SELECT ... INTO). In essence,
1324  * the result indicates if the command can be used with SPI_cursor_open
1325  *
1326  * Parameters
1327  *        plan: A plan previously prepared using SPI_prepare
1328  */
1329 bool
1330 SPI_is_cursor_plan(SPIPlanPtr plan)
1331 {
1332         CachedPlanSource *plansource;
1333         CachedPlan *cplan;
1334
1335         if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1336         {
1337                 SPI_result = SPI_ERROR_ARGUMENT;
1338                 return false;
1339         }
1340
1341         if (list_length(plan->plancache_list) != 1)
1342         {
1343                 SPI_result = 0;
1344                 return false;                   /* not exactly 1 pre-rewrite command */
1345         }
1346         plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1347
1348         /* Need _SPI_begin_call in case replanning invokes SPI-using functions */
1349         SPI_result = _SPI_begin_call(false);
1350         if (SPI_result < 0)
1351                 return false;
1352
1353         if (plan->saved)
1354         {
1355                 /* Make sure the plan is up to date */
1356                 cplan = RevalidateCachedPlan(plansource, true);
1357                 ReleaseCachedPlan(cplan, true);
1358         }
1359
1360         _SPI_end_call(false);
1361         SPI_result = 0;
1362
1363         /* Does it return tuples? */
1364         if (plansource->resultDesc)
1365                 return true;
1366
1367         return false;
1368 }
1369
1370 /*
1371  * SPI_plan_is_valid --- test whether a SPI plan is currently valid
1372  * (that is, not marked as being in need of revalidation).
1373  *
1374  * See notes for CachedPlanIsValid before using this.
1375  */
1376 bool
1377 SPI_plan_is_valid(SPIPlanPtr plan)
1378 {
1379         Assert(plan->magic == _SPI_PLAN_MAGIC);
1380         if (plan->saved)
1381         {
1382                 ListCell   *lc;
1383
1384                 foreach(lc, plan->plancache_list)
1385                 {
1386                         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1387
1388                         if (!CachedPlanIsValid(plansource))
1389                                 return false;
1390                 }
1391                 return true;
1392         }
1393         else
1394         {
1395                 /* An unsaved plan is assumed valid for its (short) lifetime */
1396                 return true;
1397         }
1398 }
1399
1400 /*
1401  * SPI_result_code_string --- convert any SPI return code to a string
1402  *
1403  * This is often useful in error messages.      Most callers will probably
1404  * only pass negative (error-case) codes, but for generality we recognize
1405  * the success codes too.
1406  */
1407 const char *
1408 SPI_result_code_string(int code)
1409 {
1410         static char buf[64];
1411
1412         switch (code)
1413         {
1414                 case SPI_ERROR_CONNECT:
1415                         return "SPI_ERROR_CONNECT";
1416                 case SPI_ERROR_COPY:
1417                         return "SPI_ERROR_COPY";
1418                 case SPI_ERROR_OPUNKNOWN:
1419                         return "SPI_ERROR_OPUNKNOWN";
1420                 case SPI_ERROR_UNCONNECTED:
1421                         return "SPI_ERROR_UNCONNECTED";
1422                 case SPI_ERROR_ARGUMENT:
1423                         return "SPI_ERROR_ARGUMENT";
1424                 case SPI_ERROR_PARAM:
1425                         return "SPI_ERROR_PARAM";
1426                 case SPI_ERROR_TRANSACTION:
1427                         return "SPI_ERROR_TRANSACTION";
1428                 case SPI_ERROR_NOATTRIBUTE:
1429                         return "SPI_ERROR_NOATTRIBUTE";
1430                 case SPI_ERROR_NOOUTFUNC:
1431                         return "SPI_ERROR_NOOUTFUNC";
1432                 case SPI_ERROR_TYPUNKNOWN:
1433                         return "SPI_ERROR_TYPUNKNOWN";
1434                 case SPI_OK_CONNECT:
1435                         return "SPI_OK_CONNECT";
1436                 case SPI_OK_FINISH:
1437                         return "SPI_OK_FINISH";
1438                 case SPI_OK_FETCH:
1439                         return "SPI_OK_FETCH";
1440                 case SPI_OK_UTILITY:
1441                         return "SPI_OK_UTILITY";
1442                 case SPI_OK_SELECT:
1443                         return "SPI_OK_SELECT";
1444                 case SPI_OK_SELINTO:
1445                         return "SPI_OK_SELINTO";
1446                 case SPI_OK_INSERT:
1447                         return "SPI_OK_INSERT";
1448                 case SPI_OK_DELETE:
1449                         return "SPI_OK_DELETE";
1450                 case SPI_OK_UPDATE:
1451                         return "SPI_OK_UPDATE";
1452                 case SPI_OK_CURSOR:
1453                         return "SPI_OK_CURSOR";
1454                 case SPI_OK_INSERT_RETURNING:
1455                         return "SPI_OK_INSERT_RETURNING";
1456                 case SPI_OK_DELETE_RETURNING:
1457                         return "SPI_OK_DELETE_RETURNING";
1458                 case SPI_OK_UPDATE_RETURNING:
1459                         return "SPI_OK_UPDATE_RETURNING";
1460         }
1461         /* Unrecognized code ... return something useful ... */
1462         sprintf(buf, "Unrecognized SPI code %d", code);
1463         return buf;
1464 }
1465
1466 /* =================== private functions =================== */
1467
1468 /*
1469  * spi_dest_startup
1470  *              Initialize to receive tuples from Executor into SPITupleTable
1471  *              of current SPI procedure
1472  */
1473 void
1474 spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
1475 {
1476         SPITupleTable *tuptable;
1477         MemoryContext oldcxt;
1478         MemoryContext tuptabcxt;
1479
1480         /*
1481          * When called by Executor _SPI_curid expected to be equal to
1482          * _SPI_connected
1483          */
1484         if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1485                 elog(ERROR, "improper call to spi_dest_startup");
1486         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1487                 elog(ERROR, "SPI stack corrupted");
1488
1489         if (_SPI_current->tuptable != NULL)
1490                 elog(ERROR, "improper call to spi_dest_startup");
1491
1492         oldcxt = _SPI_procmem();        /* switch to procedure memory context */
1493
1494         tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,
1495                                                                           "SPI TupTable",
1496                                                                           ALLOCSET_DEFAULT_MINSIZE,
1497                                                                           ALLOCSET_DEFAULT_INITSIZE,
1498                                                                           ALLOCSET_DEFAULT_MAXSIZE);
1499         MemoryContextSwitchTo(tuptabcxt);
1500
1501         _SPI_current->tuptable = tuptable = (SPITupleTable *)
1502                 palloc(sizeof(SPITupleTable));
1503         tuptable->tuptabcxt = tuptabcxt;
1504         tuptable->alloced = tuptable->free = 128;
1505         tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
1506         tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
1507
1508         MemoryContextSwitchTo(oldcxt);
1509 }
1510
1511 /*
1512  * spi_printtup
1513  *              store tuple retrieved by Executor into SPITupleTable
1514  *              of current SPI procedure
1515  */
1516 void
1517 spi_printtup(TupleTableSlot *slot, DestReceiver *self)
1518 {
1519         SPITupleTable *tuptable;
1520         MemoryContext oldcxt;
1521
1522         /*
1523          * When called by Executor _SPI_curid expected to be equal to
1524          * _SPI_connected
1525          */
1526         if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1527                 elog(ERROR, "improper call to spi_printtup");
1528         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1529                 elog(ERROR, "SPI stack corrupted");
1530
1531         tuptable = _SPI_current->tuptable;
1532         if (tuptable == NULL)
1533                 elog(ERROR, "improper call to spi_printtup");
1534
1535         oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
1536
1537         if (tuptable->free == 0)
1538         {
1539                 tuptable->free = 256;
1540                 tuptable->alloced += tuptable->free;
1541                 tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
1542                                                                           tuptable->alloced * sizeof(HeapTuple));
1543         }
1544
1545         tuptable->vals[tuptable->alloced - tuptable->free] =
1546                 ExecCopySlotTuple(slot);
1547         (tuptable->free)--;
1548
1549         MemoryContextSwitchTo(oldcxt);
1550 }
1551
1552 /*
1553  * Static functions
1554  */
1555
1556 /*
1557  * Parse and plan a querystring.
1558  *
1559  * At entry, plan->argtypes, plan->nargs, and plan->cursor_options must be
1560  * valid.  If boundParams isn't NULL then it represents parameter values
1561  * that are made available to the planner (as either estimates or hard values
1562  * depending on their PARAM_FLAG_CONST marking).  The boundParams had better
1563  * match the param types embedded in the plan!
1564  *
1565  * Results are stored into *plan (specifically, plan->plancache_list).
1566  * Note however that the result trees are all in CurrentMemoryContext
1567  * and need to be copied somewhere to survive.
1568  */
1569 static void
1570 _SPI_prepare_plan(const char *src, SPIPlanPtr plan, ParamListInfo boundParams)
1571 {
1572         List       *raw_parsetree_list;
1573         List       *plancache_list;
1574         ListCell   *list_item;
1575         ErrorContextCallback spierrcontext;
1576         Oid                *argtypes = plan->argtypes;
1577         int                     nargs = plan->nargs;
1578         int                     cursor_options = plan->cursor_options;
1579
1580         /*
1581          * Setup error traceback support for ereport()
1582          */
1583         spierrcontext.callback = _SPI_error_callback;
1584         spierrcontext.arg = (void *) src;
1585         spierrcontext.previous = error_context_stack;
1586         error_context_stack = &spierrcontext;
1587
1588         /*
1589          * Parse the request string into a list of raw parse trees.
1590          */
1591         raw_parsetree_list = pg_parse_query(src);
1592
1593         /*
1594          * Do parse analysis and rule rewrite for each raw parsetree, then cons up
1595          * a phony plancache entry for each one.
1596          */
1597         plancache_list = NIL;
1598
1599         foreach(list_item, raw_parsetree_list)
1600         {
1601                 Node       *parsetree = (Node *) lfirst(list_item);
1602                 List       *stmt_list;
1603                 CachedPlanSource *plansource;
1604                 CachedPlan *cplan;
1605
1606                 /* Need a copyObject here to keep parser from modifying raw tree */
1607                 stmt_list = pg_analyze_and_rewrite(copyObject(parsetree),
1608                                                                                    src, argtypes, nargs);
1609                 stmt_list = pg_plan_queries(stmt_list, cursor_options, boundParams);
1610
1611                 plansource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
1612                 cplan = (CachedPlan *) palloc0(sizeof(CachedPlan));
1613
1614                 plansource->raw_parse_tree = parsetree;
1615                 /* cast-away-const here is a bit ugly, but there's no reason to copy */
1616                 plansource->query_string = (char *) src;
1617                 plansource->commandTag = CreateCommandTag(parsetree);
1618                 plansource->param_types = argtypes;
1619                 plansource->num_params = nargs;
1620                 plansource->fully_planned = true;
1621                 plansource->fixed_result = false;
1622                 /* no need to set search_path, generation or saved_xmin */
1623                 plansource->resultDesc = PlanCacheComputeResultDesc(stmt_list);
1624                 plansource->plan = cplan;
1625
1626                 cplan->stmt_list = stmt_list;
1627                 cplan->fully_planned = true;
1628
1629                 plancache_list = lappend(plancache_list, plansource);
1630         }
1631
1632         plan->plancache_list = plancache_list;
1633
1634         /*
1635          * Pop the error context stack
1636          */
1637         error_context_stack = spierrcontext.previous;
1638 }
1639
1640 /*
1641  * Execute the given plan with the given parameter values
1642  *
1643  * snapshot: query snapshot to use, or InvalidSnapshot for the normal
1644  *              behavior of taking a new snapshot for each query.
1645  * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
1646  * read_only: TRUE for read-only execution (no CommandCounterIncrement)
1647  * fire_triggers: TRUE to fire AFTER triggers at end of query (normal case);
1648  *              FALSE means any AFTER triggers are postponed to end of outer query
1649  * tcount: execution tuple-count limit, or 0 for none
1650  */
1651 static int
1652 _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
1653                                   Snapshot snapshot, Snapshot crosscheck_snapshot,
1654                                   bool read_only, bool fire_triggers, long tcount)
1655 {
1656         int                     my_res = 0;
1657         uint32          my_processed = 0;
1658         Oid                     my_lastoid = InvalidOid;
1659         SPITupleTable *my_tuptable = NULL;
1660         int                     res = 0;
1661         bool            have_active_snap = ActiveSnapshotSet();
1662         ErrorContextCallback spierrcontext;
1663         CachedPlan *cplan = NULL;
1664         ListCell   *lc1;
1665
1666         /*
1667          * Setup error traceback support for ereport()
1668          */
1669         spierrcontext.callback = _SPI_error_callback;
1670         spierrcontext.arg = NULL;
1671         spierrcontext.previous = error_context_stack;
1672         error_context_stack = &spierrcontext;
1673
1674         foreach(lc1, plan->plancache_list)
1675         {
1676                 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
1677                 List       *stmt_list;
1678                 ListCell   *lc2;
1679
1680                 spierrcontext.arg = (void *) plansource->query_string;
1681
1682                 if (plan->saved)
1683                 {
1684                         /* Replan if needed, and increment plan refcount locally */
1685                         cplan = RevalidateCachedPlan(plansource, true);
1686                         stmt_list = cplan->stmt_list;
1687                 }
1688                 else
1689                 {
1690                         /* No replan here */
1691                         cplan = NULL;
1692                         stmt_list = plansource->plan->stmt_list;
1693                 }
1694
1695                 foreach(lc2, stmt_list)
1696                 {
1697                         Node       *stmt = (Node *) lfirst(lc2);
1698                         bool            canSetTag;
1699                         DestReceiver *dest;
1700                         bool            pushed_active_snap = false;
1701
1702                         _SPI_current->processed = 0;
1703                         _SPI_current->lastoid = InvalidOid;
1704                         _SPI_current->tuptable = NULL;
1705
1706                         if (IsA(stmt, PlannedStmt))
1707                         {
1708                                 canSetTag = ((PlannedStmt *) stmt)->canSetTag;
1709                         }
1710                         else
1711                         {
1712                                 /* utilities are canSetTag if only thing in list */
1713                                 canSetTag = (list_length(stmt_list) == 1);
1714
1715                                 if (IsA(stmt, CopyStmt))
1716                                 {
1717                                         CopyStmt   *cstmt = (CopyStmt *) stmt;
1718
1719                                         if (cstmt->filename == NULL)
1720                                         {
1721                                                 my_res = SPI_ERROR_COPY;
1722                                                 goto fail;
1723                                         }
1724                                 }
1725                                 else if (IsA(stmt, TransactionStmt))
1726                                 {
1727                                         my_res = SPI_ERROR_TRANSACTION;
1728                                         goto fail;
1729                                 }
1730                         }
1731
1732                         if (read_only && !CommandIsReadOnly(stmt))
1733                                 ereport(ERROR,
1734                                                 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1735                                                  /* translator: %s is a SQL statement name */
1736                                                  errmsg("%s is not allowed in a non-volatile function",
1737                                                                 CreateCommandTag(stmt))));
1738
1739                         /*
1740                          * If not read-only mode, advance the command counter before
1741                          * each command.
1742                          */
1743                         if (!read_only)
1744                                 CommandCounterIncrement();
1745
1746                         dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone);
1747
1748                         if (snapshot == InvalidSnapshot)
1749                         {
1750                                 /*
1751                                  * Default read_only behavior is to use the entry-time
1752                                  * ActiveSnapshot, if any; if read-write, grab a full new snap.
1753                                  */
1754                                 if (read_only)
1755                                 {
1756                                         if (have_active_snap)
1757                                         {
1758                                                 PushActiveSnapshot(GetActiveSnapshot());
1759                                                 pushed_active_snap = true;
1760                                         }
1761                                 }
1762                                 else
1763                                 {
1764                                         PushActiveSnapshot(GetTransactionSnapshot());
1765                                         pushed_active_snap = true;
1766                                 }
1767                         }
1768                         else
1769                         {
1770                                 /*
1771                                  * We interpret read_only with a specified snapshot to be
1772                                  * exactly that snapshot, but read-write means use the
1773                                  * snap with advancing of command ID.
1774                                  */
1775                                 if (read_only)
1776                                         PushActiveSnapshot(snapshot);
1777                                 else
1778                                         PushUpdatedSnapshot(snapshot);
1779                                 pushed_active_snap = true;
1780                         }
1781
1782                         if (IsA(stmt, PlannedStmt) &&
1783                                 ((PlannedStmt *) stmt)->utilityStmt == NULL)
1784                         {
1785                                 QueryDesc  *qdesc;
1786                                 Snapshot        snap;
1787
1788                                 if (ActiveSnapshotSet())
1789                                         snap = GetActiveSnapshot();
1790                                 else
1791                                         snap = InvalidSnapshot;
1792
1793                                 qdesc = CreateQueryDesc((PlannedStmt *) stmt,
1794                                                                                 snap, crosscheck_snapshot,
1795                                                                                 dest,
1796                                                                                 paramLI, false);
1797                                 res = _SPI_pquery(qdesc, fire_triggers,
1798                                                                   canSetTag ? tcount : 0);
1799                                 FreeQueryDesc(qdesc);
1800                         }
1801                         else
1802                         {
1803                                 ProcessUtility(stmt,
1804                                                            plansource->query_string,
1805                                                            paramLI,
1806                                                            false,               /* not top level */
1807                                                            dest,
1808                                                            NULL);
1809                                 /* Update "processed" if stmt returned tuples */
1810                                 if (_SPI_current->tuptable)
1811                                         _SPI_current->processed = _SPI_current->tuptable->alloced -
1812                                                 _SPI_current->tuptable->free;
1813                                 res = SPI_OK_UTILITY;
1814                         }
1815
1816                         if (pushed_active_snap)
1817                                 PopActiveSnapshot();
1818
1819                         /*
1820                          * The last canSetTag query sets the status values returned to
1821                          * the caller.  Be careful to free any tuptables not returned,
1822                          * to avoid intratransaction memory leak.
1823                          */
1824                         if (canSetTag)
1825                         {
1826                                 my_processed = _SPI_current->processed;
1827                                 my_lastoid = _SPI_current->lastoid;
1828                                 SPI_freetuptable(my_tuptable);
1829                                 my_tuptable = _SPI_current->tuptable;
1830                                 my_res = res;
1831                         }
1832                         else
1833                         {
1834                                 SPI_freetuptable(_SPI_current->tuptable);
1835                                 _SPI_current->tuptable = NULL;
1836                         }
1837                         /* we know that the receiver doesn't need a destroy call */
1838                         if (res < 0)
1839                         {
1840                                 my_res = res;
1841                                 goto fail;
1842                         }
1843                 }
1844
1845                 /* Done with this plan, so release refcount */
1846                 if (cplan)
1847                         ReleaseCachedPlan(cplan, true);
1848                 cplan = NULL;
1849
1850                 /*
1851                  * If not read-only mode, advance the command counter after the
1852                  * last command.  This ensures that its effects are visible, in
1853                  * case it was DDL that would affect the next CachedPlanSource.
1854                  */
1855                 if (!read_only)
1856                         CommandCounterIncrement();
1857         }
1858
1859 fail:
1860
1861         /* We no longer need the cached plan refcount, if any */
1862         if (cplan)
1863                 ReleaseCachedPlan(cplan, true);
1864
1865         /*
1866          * Pop the error context stack
1867          */
1868         error_context_stack = spierrcontext.previous;
1869
1870         /* Save results for caller */
1871         SPI_processed = my_processed;
1872         SPI_lastoid = my_lastoid;
1873         SPI_tuptable = my_tuptable;
1874
1875         /* tuptable now is caller's responsibility, not SPI's */
1876         _SPI_current->tuptable = NULL;
1877
1878         /*
1879          * If none of the queries had canSetTag, we return the last query's result
1880          * code, but not its auxiliary results (for backwards compatibility).
1881          */
1882         if (my_res == 0)
1883                 my_res = res;
1884
1885         return my_res;
1886 }
1887
1888 /*
1889  * Convert query parameters to form wanted by planner and executor
1890  */
1891 static ParamListInfo
1892 _SPI_convert_params(int nargs, Oid *argtypes,
1893                                         Datum *Values, const char *Nulls,
1894                                         int pflags)
1895 {
1896         ParamListInfo paramLI;
1897
1898         if (nargs > 0)
1899         {
1900                 int                     i;
1901
1902                 /* sizeof(ParamListInfoData) includes the first array element */
1903                 paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
1904                                                                                  (nargs - 1) *sizeof(ParamExternData));
1905                 paramLI->numParams = nargs;
1906
1907                 for (i = 0; i < nargs; i++)
1908                 {
1909                         ParamExternData *prm = &paramLI->params[i];
1910
1911                         prm->value = Values[i];
1912                         prm->isnull = (Nulls && Nulls[i] == 'n');
1913                         prm->pflags = pflags;
1914                         prm->ptype = argtypes[i];
1915                 }
1916         }
1917         else
1918                 paramLI = NULL;
1919         return paramLI;
1920 }
1921
1922 static int
1923 _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount)
1924 {
1925         int                     operation = queryDesc->operation;
1926         int                     res;
1927
1928         switch (operation)
1929         {
1930                 case CMD_SELECT:
1931                         Assert(queryDesc->plannedstmt->utilityStmt == NULL);
1932                         if (queryDesc->plannedstmt->intoClause)         /* select into table? */
1933                                 res = SPI_OK_SELINTO;
1934                         else if (queryDesc->dest->mydest != DestSPI)
1935                         {
1936                                 /* Don't return SPI_OK_SELECT if we're discarding result */
1937                                 res = SPI_OK_UTILITY;
1938                         }
1939                         else
1940                                 res = SPI_OK_SELECT;
1941                         break;
1942                 case CMD_INSERT:
1943                         if (queryDesc->plannedstmt->returningLists)
1944                                 res = SPI_OK_INSERT_RETURNING;
1945                         else
1946                                 res = SPI_OK_INSERT;
1947                         break;
1948                 case CMD_DELETE:
1949                         if (queryDesc->plannedstmt->returningLists)
1950                                 res = SPI_OK_DELETE_RETURNING;
1951                         else
1952                                 res = SPI_OK_DELETE;
1953                         break;
1954                 case CMD_UPDATE:
1955                         if (queryDesc->plannedstmt->returningLists)
1956                                 res = SPI_OK_UPDATE_RETURNING;
1957                         else
1958                                 res = SPI_OK_UPDATE;
1959                         break;
1960                 default:
1961                         return SPI_ERROR_OPUNKNOWN;
1962         }
1963
1964 #ifdef SPI_EXECUTOR_STATS
1965         if (ShowExecutorStats)
1966                 ResetUsage();
1967 #endif
1968
1969         if (fire_triggers)
1970                 AfterTriggerBeginQuery();
1971
1972         ExecutorStart(queryDesc, 0);
1973
1974         ExecutorRun(queryDesc, ForwardScanDirection, tcount);
1975
1976         _SPI_current->processed = queryDesc->estate->es_processed;
1977         _SPI_current->lastoid = queryDesc->estate->es_lastoid;
1978
1979         if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->returningLists) &&
1980                 queryDesc->dest->mydest == DestSPI)
1981         {
1982                 if (_SPI_checktuples())
1983                         elog(ERROR, "consistency check on SPI tuple count failed");
1984         }
1985
1986         /* Take care of any queued AFTER triggers */
1987         if (fire_triggers)
1988                 AfterTriggerEndQuery(queryDesc->estate);
1989
1990         ExecutorEnd(queryDesc);
1991         /* FreeQueryDesc is done by the caller */
1992
1993 #ifdef SPI_EXECUTOR_STATS
1994         if (ShowExecutorStats)
1995                 ShowUsage("SPI EXECUTOR STATS");
1996 #endif
1997
1998         return res;
1999 }
2000
2001 /*
2002  * _SPI_error_callback
2003  *
2004  * Add context information when a query invoked via SPI fails
2005  */
2006 static void
2007 _SPI_error_callback(void *arg)
2008 {
2009         const char *query = (const char *) arg;
2010         int                     syntaxerrposition;
2011
2012         /*
2013          * If there is a syntax error position, convert to internal syntax error;
2014          * otherwise treat the query as an item of context stack
2015          */
2016         syntaxerrposition = geterrposition();
2017         if (syntaxerrposition > 0)
2018         {
2019                 errposition(0);
2020                 internalerrposition(syntaxerrposition);
2021                 internalerrquery(query);
2022         }
2023         else
2024                 errcontext("SQL statement \"%s\"", query);
2025 }
2026
2027 /*
2028  * _SPI_cursor_operation()
2029  *
2030  *      Do a FETCH or MOVE in a cursor
2031  */
2032 static void
2033 _SPI_cursor_operation(Portal portal, FetchDirection direction, long count,
2034                                           DestReceiver *dest)
2035 {
2036         long            nfetched;
2037
2038         /* Check that the portal is valid */
2039         if (!PortalIsValid(portal))
2040                 elog(ERROR, "invalid portal in SPI cursor operation");
2041
2042         /* Push the SPI stack */
2043         if (_SPI_begin_call(true) < 0)
2044                 elog(ERROR, "SPI cursor operation called while not connected");
2045
2046         /* Reset the SPI result (note we deliberately don't touch lastoid) */
2047         SPI_processed = 0;
2048         SPI_tuptable = NULL;
2049         _SPI_current->processed = 0;
2050         _SPI_current->tuptable = NULL;
2051
2052         /* Run the cursor */
2053         nfetched = PortalRunFetch(portal,
2054                                                           direction,
2055                                                           count,
2056                                                           dest);
2057
2058         /*
2059          * Think not to combine this store with the preceding function call. If
2060          * the portal contains calls to functions that use SPI, then SPI_stack is
2061          * likely to move around while the portal runs.  When control returns,
2062          * _SPI_current will point to the correct stack entry... but the pointer
2063          * may be different than it was beforehand. So we must be sure to re-fetch
2064          * the pointer after the function call completes.
2065          */
2066         _SPI_current->processed = nfetched;
2067
2068         if (dest->mydest == DestSPI && _SPI_checktuples())
2069                 elog(ERROR, "consistency check on SPI tuple count failed");
2070
2071         /* Put the result into place for access by caller */
2072         SPI_processed = _SPI_current->processed;
2073         SPI_tuptable = _SPI_current->tuptable;
2074
2075         /* tuptable now is caller's responsibility, not SPI's */
2076         _SPI_current->tuptable = NULL;
2077
2078         /* Pop the SPI stack */
2079         _SPI_end_call(true);
2080 }
2081
2082
2083 static MemoryContext
2084 _SPI_execmem(void)
2085 {
2086         return MemoryContextSwitchTo(_SPI_current->execCxt);
2087 }
2088
2089 static MemoryContext
2090 _SPI_procmem(void)
2091 {
2092         return MemoryContextSwitchTo(_SPI_current->procCxt);
2093 }
2094
2095 /*
2096  * _SPI_begin_call: begin a SPI operation within a connected procedure
2097  */
2098 static int
2099 _SPI_begin_call(bool execmem)
2100 {
2101         if (_SPI_curid + 1 != _SPI_connected)
2102                 return SPI_ERROR_UNCONNECTED;
2103         _SPI_curid++;
2104         if (_SPI_current != &(_SPI_stack[_SPI_curid]))
2105                 elog(ERROR, "SPI stack corrupted");
2106
2107         if (execmem)                            /* switch to the Executor memory context */
2108                 _SPI_execmem();
2109
2110         return 0;
2111 }
2112
2113 /*
2114  * _SPI_end_call: end a SPI operation within a connected procedure
2115  *
2116  * Note: this currently has no failure return cases, so callers don't check
2117  */
2118 static int
2119 _SPI_end_call(bool procmem)
2120 {
2121         /*
2122          * We're returning to procedure where _SPI_curid == _SPI_connected - 1
2123          */
2124         _SPI_curid--;
2125
2126         if (procmem)                            /* switch to the procedure memory context */
2127         {
2128                 _SPI_procmem();
2129                 /* and free Executor memory */
2130                 MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
2131         }
2132
2133         return 0;
2134 }
2135
2136 static bool
2137 _SPI_checktuples(void)
2138 {
2139         uint32          processed = _SPI_current->processed;
2140         SPITupleTable *tuptable = _SPI_current->tuptable;
2141         bool            failed = false;
2142
2143         if (tuptable == NULL)           /* spi_dest_startup was not called */
2144                 failed = true;
2145         else if (processed != (tuptable->alloced - tuptable->free))
2146                 failed = true;
2147
2148         return failed;
2149 }
2150
2151 /*
2152  * Make an "unsaved" copy of the given plan, in a child context of parentcxt.
2153  */
2154 static SPIPlanPtr
2155 _SPI_copy_plan(SPIPlanPtr plan, MemoryContext parentcxt)
2156 {
2157         SPIPlanPtr      newplan;
2158         MemoryContext plancxt;
2159         MemoryContext oldcxt;
2160         ListCell   *lc;
2161
2162         Assert(!plan->saved);           /* not currently supported */
2163
2164         /*
2165          * Create a memory context for the plan.  We don't expect the plan to be
2166          * very large, so use smaller-than-default alloc parameters.
2167          */
2168         plancxt = AllocSetContextCreate(parentcxt,
2169                                                                         "SPI Plan",
2170                                                                         ALLOCSET_SMALL_MINSIZE,
2171                                                                         ALLOCSET_SMALL_INITSIZE,
2172                                                                         ALLOCSET_SMALL_MAXSIZE);
2173         oldcxt = MemoryContextSwitchTo(plancxt);
2174
2175         /* Copy the SPI plan into its own context */
2176         newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan));
2177         newplan->magic = _SPI_PLAN_MAGIC;
2178         newplan->saved = false;
2179         newplan->plancache_list = NIL;
2180         newplan->plancxt = plancxt;
2181         newplan->cursor_options = plan->cursor_options;
2182         newplan->nargs = plan->nargs;
2183         if (plan->nargs > 0)
2184         {
2185                 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
2186                 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
2187         }
2188         else
2189                 newplan->argtypes = NULL;
2190
2191         foreach(lc, plan->plancache_list)
2192         {
2193                 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
2194                 CachedPlanSource *newsource;
2195                 CachedPlan *cplan;
2196                 CachedPlan *newcplan;
2197
2198                 /* Note: we assume we don't need to revalidate the plan */
2199                 cplan = plansource->plan;
2200
2201                 newsource = (CachedPlanSource *) palloc0(sizeof(CachedPlanSource));
2202                 newcplan = (CachedPlan *) palloc0(sizeof(CachedPlan));
2203
2204                 newsource->raw_parse_tree = copyObject(plansource->raw_parse_tree);
2205                 newsource->query_string = pstrdup(plansource->query_string);
2206                 newsource->commandTag = plansource->commandTag;
2207                 newsource->param_types = newplan->argtypes;
2208                 newsource->num_params = newplan->nargs;
2209                 newsource->fully_planned = plansource->fully_planned;
2210                 newsource->fixed_result = plansource->fixed_result;
2211                 /* no need to worry about seach_path, generation or saved_xmin */
2212                 if (plansource->resultDesc)
2213                         newsource->resultDesc = CreateTupleDescCopy(plansource->resultDesc);
2214                 newsource->plan = newcplan;
2215
2216                 newcplan->stmt_list = copyObject(cplan->stmt_list);
2217                 newcplan->fully_planned = cplan->fully_planned;
2218
2219                 newplan->plancache_list = lappend(newplan->plancache_list, newsource);
2220         }
2221
2222         MemoryContextSwitchTo(oldcxt);
2223
2224         return newplan;
2225 }
2226
2227 /*
2228  * Make a "saved" copy of the given plan, entrusting everything to plancache.c
2229  */
2230 static SPIPlanPtr
2231 _SPI_save_plan(SPIPlanPtr plan)
2232 {
2233         SPIPlanPtr      newplan;
2234         MemoryContext plancxt;
2235         MemoryContext oldcxt;
2236         ListCell   *lc;
2237
2238         Assert(!plan->saved);           /* not currently supported */
2239
2240         /*
2241          * Create a memory context for the plan.  We don't expect the plan to be
2242          * very large, so use smaller-than-default alloc parameters.
2243          */
2244         plancxt = AllocSetContextCreate(CacheMemoryContext,
2245                                                                         "SPI Plan",
2246                                                                         ALLOCSET_SMALL_MINSIZE,
2247                                                                         ALLOCSET_SMALL_INITSIZE,
2248                                                                         ALLOCSET_SMALL_MAXSIZE);
2249         oldcxt = MemoryContextSwitchTo(plancxt);
2250
2251         /* Copy the SPI plan into its own context */
2252         newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan));
2253         newplan->magic = _SPI_PLAN_MAGIC;
2254         newplan->saved = true;
2255         newplan->plancache_list = NIL;
2256         newplan->plancxt = plancxt;
2257         newplan->cursor_options = plan->cursor_options;
2258         newplan->nargs = plan->nargs;
2259         if (plan->nargs > 0)
2260         {
2261                 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
2262                 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
2263         }
2264         else
2265                 newplan->argtypes = NULL;
2266
2267         foreach(lc, plan->plancache_list)
2268         {
2269                 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
2270                 CachedPlanSource *newsource;
2271                 CachedPlan *cplan;
2272
2273                 /* Note: we assume we don't need to revalidate the plan */
2274                 cplan = plansource->plan;
2275
2276                 newsource = CreateCachedPlan(plansource->raw_parse_tree,
2277                                                                          plansource->query_string,
2278                                                                          plansource->commandTag,
2279                                                                          newplan->argtypes,
2280                                                                          newplan->nargs,
2281                                                                          newplan->cursor_options,
2282                                                                          cplan->stmt_list,
2283                                                                          true,
2284                                                                          false);
2285
2286                 newplan->plancache_list = lappend(newplan->plancache_list, newsource);
2287         }
2288
2289         MemoryContextSwitchTo(oldcxt);
2290
2291         return newplan;
2292 }