PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
spi.c
Go to the documentation of this file.
1 /*-------------------------------------------------------------------------
2  *
3  * spi.c
4  * Server Programming Interface
5  *
6  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  * src/backend/executor/spi.c
12  *
13  *-------------------------------------------------------------------------
14  */
15 #include "postgres.h"
16 
17 #include "access/htup_details.h"
18 #include "access/printtup.h"
19 #include "access/sysattr.h"
20 #include "access/xact.h"
21 #include "catalog/heap.h"
22 #include "catalog/pg_type.h"
23 #include "commands/trigger.h"
24 #include "executor/executor.h"
25 #include "executor/spi_priv.h"
26 #include "miscadmin.h"
27 #include "tcop/pquery.h"
28 #include "tcop/utility.h"
29 #include "utils/builtins.h"
30 #include "utils/datum.h"
31 #include "utils/lsyscache.h"
32 #include "utils/memutils.h"
33 #include "utils/rel.h"
34 #include "utils/snapmgr.h"
35 #include "utils/syscache.h"
36 #include "utils/typcache.h"
37 
38 
39 uint64 SPI_processed = 0;
43 
46 static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */
47 static int _SPI_connected = -1; /* current stack index */
48 
49 static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
50  ParamListInfo paramLI, bool read_only);
51 
52 static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan);
53 
54 static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan);
55 
56 static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
57  Snapshot snapshot, Snapshot crosscheck_snapshot,
58  bool read_only, bool fire_triggers, uint64 tcount);
59 
60 static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
61  Datum *Values, const char *Nulls);
62 
63 static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount);
64 
65 static void _SPI_error_callback(void *arg);
66 
67 static void _SPI_cursor_operation(Portal portal,
68  FetchDirection direction, long count,
69  DestReceiver *dest);
70 
73 
74 static int _SPI_begin_call(bool execmem);
75 static int _SPI_end_call(bool procmem);
76 static MemoryContext _SPI_execmem(void);
77 static MemoryContext _SPI_procmem(void);
78 static bool _SPI_checktuples(void);
79 
80 
81 /* =================== interface functions =================== */
82 
83 int
85 {
86  int newdepth;
87 
88  /* Enlarge stack if necessary */
89  if (_SPI_stack == NULL)
90  {
91  if (_SPI_connected != -1 || _SPI_stack_depth != 0)
92  elog(ERROR, "SPI stack corrupted");
93  newdepth = 16;
94  _SPI_stack = (_SPI_connection *)
96  newdepth * sizeof(_SPI_connection));
97  _SPI_stack_depth = newdepth;
98  }
99  else
100  {
102  elog(ERROR, "SPI stack corrupted");
103  if (_SPI_stack_depth == _SPI_connected + 1)
104  {
105  newdepth = _SPI_stack_depth * 2;
106  _SPI_stack = (_SPI_connection *)
107  repalloc(_SPI_stack,
108  newdepth * sizeof(_SPI_connection));
109  _SPI_stack_depth = newdepth;
110  }
111  }
112 
113  /* Enter new stack level */
114  _SPI_connected++;
116 
117  _SPI_current = &(_SPI_stack[_SPI_connected]);
118  _SPI_current->processed = 0;
119  _SPI_current->lastoid = InvalidOid;
120  _SPI_current->tuptable = NULL;
121  slist_init(&_SPI_current->tuptables);
122  _SPI_current->procCxt = NULL; /* in case we fail to create 'em */
123  _SPI_current->execCxt = NULL;
124  _SPI_current->connectSubid = GetCurrentSubTransactionId();
125 
126  /*
127  * Create memory contexts for this procedure
128  *
129  * XXX it would be better to use PortalContext as the parent context, but
130  * we may not be inside a portal (consider deferred-trigger execution).
131  * Perhaps CurTransactionContext would do? For now it doesn't matter
132  * because we clean up explicitly in AtEOSubXact_SPI().
133  */
135  "SPI Proc",
138  "SPI Exec",
140  /* ... and switch to procedure's context */
141  _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
142 
143  return SPI_OK_CONNECT;
144 }
145 
146 int
148 {
149  int res;
150 
151  res = _SPI_begin_call(false); /* live in procedure memory */
152  if (res < 0)
153  return res;
154 
155  /* Restore memory context as it was before procedure call */
156  MemoryContextSwitchTo(_SPI_current->savedcxt);
157 
158  /* Release memory used in procedure call (including tuptables) */
159  MemoryContextDelete(_SPI_current->execCxt);
160  _SPI_current->execCxt = NULL;
161  MemoryContextDelete(_SPI_current->procCxt);
162  _SPI_current->procCxt = NULL;
163 
164  /*
165  * Reset result variables, especially SPI_tuptable which is probably
166  * pointing at a just-deleted tuptable
167  */
168  SPI_processed = 0;
170  SPI_tuptable = NULL;
171 
172  /* Exit stack level */
173  _SPI_connected--;
174  if (_SPI_connected < 0)
175  _SPI_current = NULL;
176  else
177  _SPI_current = &(_SPI_stack[_SPI_connected]);
178 
179  return SPI_OK_FINISH;
180 }
181 
182 /*
183  * Clean up SPI state at transaction commit or abort.
184  */
185 void
186 AtEOXact_SPI(bool isCommit)
187 {
188  /*
189  * Note that memory contexts belonging to SPI stack entries will be freed
190  * automatically, so we can ignore them here. We just need to restore our
191  * static variables to initial state.
192  */
193  if (isCommit && _SPI_connected != -1)
195  (errcode(ERRCODE_WARNING),
196  errmsg("transaction left non-empty SPI stack"),
197  errhint("Check for missing \"SPI_finish\" calls.")));
198 
199  _SPI_current = _SPI_stack = NULL;
200  _SPI_stack_depth = 0;
201  _SPI_connected = -1;
202  SPI_processed = 0;
204  SPI_tuptable = NULL;
205 }
206 
207 /*
208  * Clean up SPI state at subtransaction commit or abort.
209  *
210  * During commit, there shouldn't be any unclosed entries remaining from
211  * the current subtransaction; we emit a warning if any are found.
212  */
213 void
214 AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
215 {
216  bool found = false;
217 
218  while (_SPI_connected >= 0)
219  {
220  _SPI_connection *connection = &(_SPI_stack[_SPI_connected]);
221 
222  if (connection->connectSubid != mySubid)
223  break; /* couldn't be any underneath it either */
224 
225  found = true;
226 
227  /*
228  * Release procedure memory explicitly (see note in SPI_connect)
229  */
230  if (connection->execCxt)
231  {
232  MemoryContextDelete(connection->execCxt);
233  connection->execCxt = NULL;
234  }
235  if (connection->procCxt)
236  {
237  MemoryContextDelete(connection->procCxt);
238  connection->procCxt = NULL;
239  }
240 
241  /*
242  * Pop the stack entry and reset global variables. Unlike
243  * SPI_finish(), we don't risk switching to memory contexts that might
244  * be already gone.
245  */
246  _SPI_connected--;
247  if (_SPI_connected < 0)
248  _SPI_current = NULL;
249  else
250  _SPI_current = &(_SPI_stack[_SPI_connected]);
251  SPI_processed = 0;
253  SPI_tuptable = NULL;
254  }
255 
256  if (found && isCommit)
258  (errcode(ERRCODE_WARNING),
259  errmsg("subtransaction left non-empty SPI stack"),
260  errhint("Check for missing \"SPI_finish\" calls.")));
261 
262  /*
263  * If we are aborting a subtransaction and there is an open SPI context
264  * surrounding the subxact, clean up to prevent memory leakage.
265  */
266  if (_SPI_current && !isCommit)
267  {
268  slist_mutable_iter siter;
269 
270  /* free Executor memory the same as _SPI_end_call would do */
272 
273  /* throw away any tuple tables created within current subxact */
274  slist_foreach_modify(siter, &_SPI_current->tuptables)
275  {
276  SPITupleTable *tuptable;
277 
278  tuptable = slist_container(SPITupleTable, next, siter.cur);
279  if (tuptable->subid >= mySubid)
280  {
281  /*
282  * If we used SPI_freetuptable() here, its internal search of
283  * the tuptables list would make this operation O(N^2).
284  * Instead, just free the tuptable manually. This should
285  * match what SPI_freetuptable() does.
286  */
287  slist_delete_current(&siter);
288  if (tuptable == _SPI_current->tuptable)
289  _SPI_current->tuptable = NULL;
290  if (tuptable == SPI_tuptable)
291  SPI_tuptable = NULL;
292  MemoryContextDelete(tuptable->tuptabcxt);
293  }
294  }
295  /* in particular we should have gotten rid of any in-progress table */
296  Assert(_SPI_current->tuptable == NULL);
297  }
298 }
299 
300 
301 /* Parse, plan, and execute a query string */
302 int
303 SPI_execute(const char *src, bool read_only, long tcount)
304 {
305  _SPI_plan plan;
306  int res;
307 
308  if (src == NULL || tcount < 0)
309  return SPI_ERROR_ARGUMENT;
310 
311  res = _SPI_begin_call(true);
312  if (res < 0)
313  return res;
314 
315  memset(&plan, 0, sizeof(_SPI_plan));
316  plan.magic = _SPI_PLAN_MAGIC;
317  plan.cursor_options = 0;
318 
319  _SPI_prepare_oneshot_plan(src, &plan);
320 
321  res = _SPI_execute_plan(&plan, NULL,
323  read_only, true, tcount);
324 
325  _SPI_end_call(true);
326  return res;
327 }
328 
329 /* Obsolete version of SPI_execute */
330 int
331 SPI_exec(const char *src, long tcount)
332 {
333  return SPI_execute(src, false, tcount);
334 }
335 
336 /* Execute a previously prepared plan */
337 int
338 SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
339  bool read_only, long tcount)
340 {
341  int res;
342 
343  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
344  return SPI_ERROR_ARGUMENT;
345 
346  if (plan->nargs > 0 && Values == NULL)
347  return SPI_ERROR_PARAM;
348 
349  res = _SPI_begin_call(true);
350  if (res < 0)
351  return res;
352 
353  res = _SPI_execute_plan(plan,
354  _SPI_convert_params(plan->nargs, plan->argtypes,
355  Values, Nulls),
357  read_only, true, tcount);
358 
359  _SPI_end_call(true);
360  return res;
361 }
362 
363 /* Obsolete version of SPI_execute_plan */
364 int
365 SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
366 {
367  return SPI_execute_plan(plan, Values, Nulls, false, tcount);
368 }
369 
370 /* Execute a previously prepared plan */
371 int
373  bool read_only, long tcount)
374 {
375  int res;
376 
377  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
378  return SPI_ERROR_ARGUMENT;
379 
380  res = _SPI_begin_call(true);
381  if (res < 0)
382  return res;
383 
384  res = _SPI_execute_plan(plan, params,
386  read_only, true, tcount);
387 
388  _SPI_end_call(true);
389  return res;
390 }
391 
392 /*
393  * SPI_execute_snapshot -- identical to SPI_execute_plan, except that we allow
394  * the caller to specify exactly which snapshots to use, which will be
395  * registered here. Also, the caller may specify that AFTER triggers should be
396  * queued as part of the outer query rather than being fired immediately at the
397  * end of the command.
398  *
399  * This is currently not documented in spi.sgml because it is only intended
400  * for use by RI triggers.
401  *
402  * Passing snapshot == InvalidSnapshot will select the normal behavior of
403  * fetching a new snapshot for each query.
404  */
405 int
407  Datum *Values, const char *Nulls,
408  Snapshot snapshot, Snapshot crosscheck_snapshot,
409  bool read_only, bool fire_triggers, long tcount)
410 {
411  int res;
412 
413  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
414  return SPI_ERROR_ARGUMENT;
415 
416  if (plan->nargs > 0 && Values == NULL)
417  return SPI_ERROR_PARAM;
418 
419  res = _SPI_begin_call(true);
420  if (res < 0)
421  return res;
422 
423  res = _SPI_execute_plan(plan,
424  _SPI_convert_params(plan->nargs, plan->argtypes,
425  Values, Nulls),
426  snapshot, crosscheck_snapshot,
427  read_only, fire_triggers, tcount);
428 
429  _SPI_end_call(true);
430  return res;
431 }
432 
433 /*
434  * SPI_execute_with_args -- plan and execute a query with supplied arguments
435  *
436  * This is functionally equivalent to SPI_prepare followed by
437  * SPI_execute_plan.
438  */
439 int
440 SPI_execute_with_args(const char *src,
441  int nargs, Oid *argtypes,
442  Datum *Values, const char *Nulls,
443  bool read_only, long tcount)
444 {
445  int res;
446  _SPI_plan plan;
447  ParamListInfo paramLI;
448 
449  if (src == NULL || nargs < 0 || tcount < 0)
450  return SPI_ERROR_ARGUMENT;
451 
452  if (nargs > 0 && (argtypes == NULL || Values == NULL))
453  return SPI_ERROR_PARAM;
454 
455  res = _SPI_begin_call(true);
456  if (res < 0)
457  return res;
458 
459  memset(&plan, 0, sizeof(_SPI_plan));
460  plan.magic = _SPI_PLAN_MAGIC;
461  plan.cursor_options = 0;
462  plan.nargs = nargs;
463  plan.argtypes = argtypes;
464  plan.parserSetup = NULL;
465  plan.parserSetupArg = NULL;
466 
467  paramLI = _SPI_convert_params(nargs, argtypes,
468  Values, Nulls);
469 
470  _SPI_prepare_oneshot_plan(src, &plan);
471 
472  res = _SPI_execute_plan(&plan, paramLI,
474  read_only, true, tcount);
475 
476  _SPI_end_call(true);
477  return res;
478 }
479 
481 SPI_prepare(const char *src, int nargs, Oid *argtypes)
482 {
483  return SPI_prepare_cursor(src, nargs, argtypes, 0);
484 }
485 
487 SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
488  int cursorOptions)
489 {
490  _SPI_plan plan;
491  SPIPlanPtr result;
492 
493  if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
494  {
496  return NULL;
497  }
498 
499  SPI_result = _SPI_begin_call(true);
500  if (SPI_result < 0)
501  return NULL;
502 
503  memset(&plan, 0, sizeof(_SPI_plan));
504  plan.magic = _SPI_PLAN_MAGIC;
505  plan.cursor_options = cursorOptions;
506  plan.nargs = nargs;
507  plan.argtypes = argtypes;
508  plan.parserSetup = NULL;
509  plan.parserSetupArg = NULL;
510 
511  _SPI_prepare_plan(src, &plan);
512 
513  /* copy plan to procedure context */
514  result = _SPI_make_plan_non_temp(&plan);
515 
516  _SPI_end_call(true);
517 
518  return result;
519 }
520 
522 SPI_prepare_params(const char *src,
523  ParserSetupHook parserSetup,
524  void *parserSetupArg,
525  int cursorOptions)
526 {
527  _SPI_plan plan;
528  SPIPlanPtr result;
529 
530  if (src == NULL)
531  {
533  return NULL;
534  }
535 
536  SPI_result = _SPI_begin_call(true);
537  if (SPI_result < 0)
538  return NULL;
539 
540  memset(&plan, 0, sizeof(_SPI_plan));
541  plan.magic = _SPI_PLAN_MAGIC;
542  plan.cursor_options = cursorOptions;
543  plan.nargs = 0;
544  plan.argtypes = NULL;
545  plan.parserSetup = parserSetup;
546  plan.parserSetupArg = parserSetupArg;
547 
548  _SPI_prepare_plan(src, &plan);
549 
550  /* copy plan to procedure context */
551  result = _SPI_make_plan_non_temp(&plan);
552 
553  _SPI_end_call(true);
554 
555  return result;
556 }
557 
558 int
560 {
561  ListCell *lc;
562 
563  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
564  plan->saved || plan->oneshot)
565  return SPI_ERROR_ARGUMENT;
566 
567  /*
568  * Mark it saved, reparent it under CacheMemoryContext, and mark all the
569  * component CachedPlanSources as saved. This sequence cannot fail
570  * partway through, so there's no risk of long-term memory leakage.
571  */
572  plan->saved = true;
574 
575  foreach(lc, plan->plancache_list)
576  {
577  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
578 
579  SaveCachedPlan(plansource);
580  }
581 
582  return 0;
583 }
584 
587 {
588  SPIPlanPtr newplan;
589 
590  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
591  {
593  return NULL;
594  }
595 
596  SPI_result = _SPI_begin_call(false); /* don't change context */
597  if (SPI_result < 0)
598  return NULL;
599 
600  newplan = _SPI_save_plan(plan);
601 
602  SPI_result = _SPI_end_call(false);
603 
604  return newplan;
605 }
606 
607 int
609 {
610  ListCell *lc;
611 
612  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
613  return SPI_ERROR_ARGUMENT;
614 
615  /* Release the plancache entries */
616  foreach(lc, plan->plancache_list)
617  {
618  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
619 
620  DropCachedPlan(plansource);
621  }
622 
623  /* Now get rid of the _SPI_plan and subsidiary data in its plancxt */
625 
626  return 0;
627 }
628 
629 HeapTuple
631 {
632  MemoryContext oldcxt;
633  HeapTuple ctuple;
634 
635  if (tuple == NULL)
636  {
638  return NULL;
639  }
640 
641  if (_SPI_current == NULL)
642  {
644  return NULL;
645  }
646 
647  oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
648 
649  ctuple = heap_copytuple(tuple);
650 
651  MemoryContextSwitchTo(oldcxt);
652 
653  return ctuple;
654 }
655 
658 {
659  MemoryContext oldcxt;
660  HeapTupleHeader dtup;
661 
662  if (tuple == NULL || tupdesc == NULL)
663  {
665  return NULL;
666  }
667 
668  if (_SPI_current == NULL)
669  {
671  return NULL;
672  }
673 
674  /* For RECORD results, make sure a typmod has been assigned */
675  if (tupdesc->tdtypeid == RECORDOID &&
676  tupdesc->tdtypmod < 0)
677  assign_record_type_typmod(tupdesc);
678 
679  oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
680 
681  dtup = DatumGetHeapTupleHeader(heap_copy_tuple_as_datum(tuple, tupdesc));
682 
683  MemoryContextSwitchTo(oldcxt);
684 
685  return dtup;
686 }
687 
688 HeapTuple
689 SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
690  Datum *Values, const char *Nulls)
691 {
692  MemoryContext oldcxt;
693  HeapTuple mtuple;
694  int numberOfAttributes;
695  Datum *v;
696  bool *n;
697  int i;
698 
699  if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
700  {
702  return NULL;
703  }
704 
705  if (_SPI_current == NULL)
706  {
708  return NULL;
709  }
710 
711  oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
712 
713  SPI_result = 0;
714 
715  numberOfAttributes = rel->rd_att->natts;
716  v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
717  n = (bool *) palloc(numberOfAttributes * sizeof(bool));
718 
719  /* fetch old values and nulls */
720  heap_deform_tuple(tuple, rel->rd_att, v, n);
721 
722  /* replace values and nulls */
723  for (i = 0; i < natts; i++)
724  {
725  if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
726  break;
727  v[attnum[i] - 1] = Values[i];
728  n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? true : false;
729  }
730 
731  if (i == natts) /* no errors in *attnum */
732  {
733  mtuple = heap_form_tuple(rel->rd_att, v, n);
734 
735  /*
736  * copy the identification info of the old tuple: t_ctid, t_self, and
737  * OID (if any)
738  */
739  mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
740  mtuple->t_self = tuple->t_self;
741  mtuple->t_tableOid = tuple->t_tableOid;
742  if (rel->rd_att->tdhasoid)
743  HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
744  }
745  else
746  {
747  mtuple = NULL;
749  }
750 
751  pfree(v);
752  pfree(n);
753 
754  MemoryContextSwitchTo(oldcxt);
755 
756  return mtuple;
757 }
758 
759 int
760 SPI_fnumber(TupleDesc tupdesc, const char *fname)
761 {
762  int res;
763  Form_pg_attribute sysatt;
764 
765  for (res = 0; res < tupdesc->natts; res++)
766  {
767  if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0 &&
768  !tupdesc->attrs[res]->attisdropped)
769  return res + 1;
770  }
771 
772  sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ );
773  if (sysatt != NULL)
774  return sysatt->attnum;
775 
776  /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
777  return SPI_ERROR_NOATTRIBUTE;
778 }
779 
780 char *
781 SPI_fname(TupleDesc tupdesc, int fnumber)
782 {
783  Form_pg_attribute att;
784 
785  SPI_result = 0;
786 
787  if (fnumber > tupdesc->natts || fnumber == 0 ||
789  {
791  return NULL;
792  }
793 
794  if (fnumber > 0)
795  att = tupdesc->attrs[fnumber - 1];
796  else
797  att = SystemAttributeDefinition(fnumber, true);
798 
799  return pstrdup(NameStr(att->attname));
800 }
801 
802 char *
803 SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
804 {
805  Datum val;
806  bool isnull;
807  Oid typoid,
808  foutoid;
809  bool typisvarlena;
810 
811  SPI_result = 0;
812 
813  if (fnumber > tupdesc->natts || fnumber == 0 ||
815  {
817  return NULL;
818  }
819 
820  val = heap_getattr(tuple, fnumber, tupdesc, &isnull);
821  if (isnull)
822  return NULL;
823 
824  if (fnumber > 0)
825  typoid = tupdesc->attrs[fnumber - 1]->atttypid;
826  else
827  typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
828 
829  getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
830 
831  return OidOutputFunctionCall(foutoid, val);
832 }
833 
834 Datum
835 SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
836 {
837  SPI_result = 0;
838 
839  if (fnumber > tupdesc->natts || fnumber == 0 ||
841  {
843  *isnull = true;
844  return (Datum) NULL;
845  }
846 
847  return heap_getattr(tuple, fnumber, tupdesc, isnull);
848 }
849 
850 char *
851 SPI_gettype(TupleDesc tupdesc, int fnumber)
852 {
853  Oid typoid;
854  HeapTuple typeTuple;
855  char *result;
856 
857  SPI_result = 0;
858 
859  if (fnumber > tupdesc->natts || fnumber == 0 ||
861  {
863  return NULL;
864  }
865 
866  if (fnumber > 0)
867  typoid = tupdesc->attrs[fnumber - 1]->atttypid;
868  else
869  typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
870 
871  typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
872 
873  if (!HeapTupleIsValid(typeTuple))
874  {
876  return NULL;
877  }
878 
879  result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
880  ReleaseSysCache(typeTuple);
881  return result;
882 }
883 
884 /*
885  * Get the data type OID for a column.
886  *
887  * There's nothing similar for typmod and typcollation. The rare consumers
888  * thereof should inspect the TupleDesc directly.
889  */
890 Oid
891 SPI_gettypeid(TupleDesc tupdesc, int fnumber)
892 {
893  SPI_result = 0;
894 
895  if (fnumber > tupdesc->natts || fnumber == 0 ||
897  {
899  return InvalidOid;
900  }
901 
902  if (fnumber > 0)
903  return tupdesc->attrs[fnumber - 1]->atttypid;
904  else
905  return (SystemAttributeDefinition(fnumber, true))->atttypid;
906 }
907 
908 char *
910 {
911  return pstrdup(RelationGetRelationName(rel));
912 }
913 
914 char *
916 {
918 }
919 
920 void *
922 {
923  if (_SPI_current == NULL)
924  elog(ERROR, "SPI_palloc called while not connected to SPI");
925 
926  return MemoryContextAlloc(_SPI_current->savedcxt, size);
927 }
928 
929 void *
930 SPI_repalloc(void *pointer, Size size)
931 {
932  /* No longer need to worry which context chunk was in... */
933  return repalloc(pointer, size);
934 }
935 
936 void
937 SPI_pfree(void *pointer)
938 {
939  /* No longer need to worry which context chunk was in... */
940  pfree(pointer);
941 }
942 
943 Datum
944 SPI_datumTransfer(Datum value, bool typByVal, int typLen)
945 {
946  MemoryContext oldcxt;
947  Datum result;
948 
949  if (_SPI_current == NULL)
950  elog(ERROR, "SPI_datumTransfer called while not connected to SPI");
951 
952  oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
953 
954  result = datumTransfer(value, typByVal, typLen);
955 
956  MemoryContextSwitchTo(oldcxt);
957 
958  return result;
959 }
960 
961 void
963 {
964  /* No longer need to worry which context tuple was in... */
965  heap_freetuple(tuple);
966 }
967 
968 void
970 {
971  bool found = false;
972 
973  /* ignore call if NULL pointer */
974  if (tuptable == NULL)
975  return;
976 
977  /*
978  * Search only the topmost SPI context for a matching tuple table.
979  */
980  if (_SPI_current != NULL)
981  {
982  slist_mutable_iter siter;
983 
984  /* find tuptable in active list, then remove it */
985  slist_foreach_modify(siter, &_SPI_current->tuptables)
986  {
987  SPITupleTable *tt;
988 
989  tt = slist_container(SPITupleTable, next, siter.cur);
990  if (tt == tuptable)
991  {
992  slist_delete_current(&siter);
993  found = true;
994  break;
995  }
996  }
997  }
998 
999  /*
1000  * Refuse the deletion if we didn't find it in the topmost SPI context.
1001  * This is primarily a guard against double deletion, but might prevent
1002  * other errors as well. Since the worst consequence of not deleting a
1003  * tuptable would be a transient memory leak, this is just a WARNING.
1004  */
1005  if (!found)
1006  {
1007  elog(WARNING, "attempt to delete invalid SPITupleTable %p", tuptable);
1008  return;
1009  }
1010 
1011  /* for safety, reset global variables that might point at tuptable */
1012  if (tuptable == _SPI_current->tuptable)
1013  _SPI_current->tuptable = NULL;
1014  if (tuptable == SPI_tuptable)
1015  SPI_tuptable = NULL;
1016 
1017  /* release all memory belonging to tuptable */
1018  MemoryContextDelete(tuptable->tuptabcxt);
1019 }
1020 
1021 
1022 /*
1023  * SPI_cursor_open()
1024  *
1025  * Open a prepared SPI plan as a portal
1026  */
1027 Portal
1028 SPI_cursor_open(const char *name, SPIPlanPtr plan,
1029  Datum *Values, const char *Nulls,
1030  bool read_only)
1031 {
1032  Portal portal;
1033  ParamListInfo paramLI;
1034 
1035  /* build transient ParamListInfo in caller's context */
1036  paramLI = _SPI_convert_params(plan->nargs, plan->argtypes,
1037  Values, Nulls);
1038 
1039  portal = SPI_cursor_open_internal(name, plan, paramLI, read_only);
1040 
1041  /* done with the transient ParamListInfo */
1042  if (paramLI)
1043  pfree(paramLI);
1044 
1045  return portal;
1046 }
1047 
1048 
1049 /*
1050  * SPI_cursor_open_with_args()
1051  *
1052  * Parse and plan a query and open it as a portal.
1053  */
1054 Portal
1056  const char *src,
1057  int nargs, Oid *argtypes,
1058  Datum *Values, const char *Nulls,
1059  bool read_only, int cursorOptions)
1060 {
1061  Portal result;
1062  _SPI_plan plan;
1063  ParamListInfo paramLI;
1064 
1065  if (src == NULL || nargs < 0)
1066  elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments");
1067 
1068  if (nargs > 0 && (argtypes == NULL || Values == NULL))
1069  elog(ERROR, "SPI_cursor_open_with_args called with missing parameters");
1070 
1071  SPI_result = _SPI_begin_call(true);
1072  if (SPI_result < 0)
1073  elog(ERROR, "SPI_cursor_open_with_args called while not connected");
1074 
1075  memset(&plan, 0, sizeof(_SPI_plan));
1076  plan.magic = _SPI_PLAN_MAGIC;
1077  plan.cursor_options = cursorOptions;
1078  plan.nargs = nargs;
1079  plan.argtypes = argtypes;
1080  plan.parserSetup = NULL;
1081  plan.parserSetupArg = NULL;
1082 
1083  /* build transient ParamListInfo in executor context */
1084  paramLI = _SPI_convert_params(nargs, argtypes,
1085  Values, Nulls);
1086 
1087  _SPI_prepare_plan(src, &plan);
1088 
1089  /* We needn't copy the plan; SPI_cursor_open_internal will do so */
1090 
1091  result = SPI_cursor_open_internal(name, &plan, paramLI, read_only);
1092 
1093  /* And clean up */
1094  _SPI_end_call(true);
1095 
1096  return result;
1097 }
1098 
1099 
1100 /*
1101  * SPI_cursor_open_with_paramlist()
1102  *
1103  * Same as SPI_cursor_open except that parameters (if any) are passed
1104  * as a ParamListInfo, which supports dynamic parameter set determination
1105  */
1106 Portal
1108  ParamListInfo params, bool read_only)
1109 {
1110  return SPI_cursor_open_internal(name, plan, params, read_only);
1111 }
1112 
1113 
1114 /*
1115  * SPI_cursor_open_internal()
1116  *
1117  * Common code for SPI_cursor_open variants
1118  */
1119 static Portal
1121  ParamListInfo paramLI, bool read_only)
1122 {
1123  CachedPlanSource *plansource;
1124  CachedPlan *cplan;
1125  List *stmt_list;
1126  char *query_string;
1127  Snapshot snapshot;
1128  MemoryContext oldcontext;
1129  Portal portal;
1130  ErrorContextCallback spierrcontext;
1131 
1132  /*
1133  * Check that the plan is something the Portal code will special-case as
1134  * returning one tupleset.
1135  */
1136  if (!SPI_is_cursor_plan(plan))
1137  {
1138  /* try to give a good error message */
1139  if (list_length(plan->plancache_list) != 1)
1140  ereport(ERROR,
1141  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
1142  errmsg("cannot open multi-query plan as cursor")));
1143  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1144  ereport(ERROR,
1145  (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
1146  /* translator: %s is name of a SQL command, eg INSERT */
1147  errmsg("cannot open %s query as cursor",
1148  plansource->commandTag)));
1149  }
1150 
1151  Assert(list_length(plan->plancache_list) == 1);
1152  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1153 
1154  /* Push the SPI stack */
1155  if (_SPI_begin_call(true) < 0)
1156  elog(ERROR, "SPI_cursor_open called while not connected");
1157 
1158  /* Reset SPI result (note we deliberately don't touch lastoid) */
1159  SPI_processed = 0;
1160  SPI_tuptable = NULL;
1161  _SPI_current->processed = 0;
1162  _SPI_current->tuptable = NULL;
1163 
1164  /* Create the portal */
1165  if (name == NULL || name[0] == '\0')
1166  {
1167  /* Use a random nonconflicting name */
1168  portal = CreateNewPortal();
1169  }
1170  else
1171  {
1172  /* In this path, error if portal of same name already exists */
1173  portal = CreatePortal(name, false, false);
1174  }
1175 
1176  /* Copy the plan's query string into the portal */
1177  query_string = MemoryContextStrdup(PortalGetHeapMemory(portal),
1178  plansource->query_string);
1179 
1180  /*
1181  * Setup error traceback support for ereport(), in case GetCachedPlan
1182  * throws an error.
1183  */
1184  spierrcontext.callback = _SPI_error_callback;
1185  spierrcontext.arg = (void *) plansource->query_string;
1186  spierrcontext.previous = error_context_stack;
1187  error_context_stack = &spierrcontext;
1188 
1189  /*
1190  * Note: for a saved plan, we mustn't have any failure occur between
1191  * GetCachedPlan and PortalDefineQuery; that would result in leaking our
1192  * plancache refcount.
1193  */
1194 
1195  /* Replan if needed, and increment plan refcount for portal */
1196  cplan = GetCachedPlan(plansource, paramLI, false);
1197  stmt_list = cplan->stmt_list;
1198 
1199  /* Pop the error context stack */
1200  error_context_stack = spierrcontext.previous;
1201 
1202  if (!plan->saved)
1203  {
1204  /*
1205  * We don't want the portal to depend on an unsaved CachedPlanSource,
1206  * so must copy the plan into the portal's context. An error here
1207  * will result in leaking our refcount on the plan, but it doesn't
1208  * matter because the plan is unsaved and hence transient anyway.
1209  */
1210  oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
1211  stmt_list = copyObject(stmt_list);
1212  MemoryContextSwitchTo(oldcontext);
1213  ReleaseCachedPlan(cplan, false);
1214  cplan = NULL; /* portal shouldn't depend on cplan */
1215  }
1216 
1217  /*
1218  * Set up the portal.
1219  */
1220  PortalDefineQuery(portal,
1221  NULL, /* no statement name */
1222  query_string,
1223  plansource->commandTag,
1224  stmt_list,
1225  cplan);
1226 
1227  /*
1228  * Set up options for portal. Default SCROLL type is chosen the same way
1229  * as PerformCursorOpen does it.
1230  */
1231  portal->cursorOptions = plan->cursor_options;
1233  {
1234  if (list_length(stmt_list) == 1 &&
1235  castNode(PlannedStmt, linitial(stmt_list))->commandType != CMD_UTILITY &&
1236  castNode(PlannedStmt, linitial(stmt_list))->rowMarks == NIL &&
1237  ExecSupportsBackwardScan(castNode(PlannedStmt, linitial(stmt_list))->planTree))
1238  portal->cursorOptions |= CURSOR_OPT_SCROLL;
1239  else
1241  }
1242 
1243  /*
1244  * Disallow SCROLL with SELECT FOR UPDATE. This is not redundant with the
1245  * check in transformDeclareCursorStmt because the cursor options might
1246  * not have come through there.
1247  */
1248  if (portal->cursorOptions & CURSOR_OPT_SCROLL)
1249  {
1250  if (list_length(stmt_list) == 1 &&
1251  castNode(PlannedStmt, linitial(stmt_list))->commandType != CMD_UTILITY &&
1252  castNode(PlannedStmt, linitial(stmt_list))->rowMarks != NIL)
1253  ereport(ERROR,
1254  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1255  errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"),
1256  errdetail("Scrollable cursors must be READ ONLY.")));
1257  }
1258 
1259  /*
1260  * If told to be read-only, or in parallel mode, verify that this query is
1261  * in fact read-only. This can't be done earlier because we need to look
1262  * at the finished, planned queries. (In particular, we don't want to do
1263  * it between GetCachedPlan and PortalDefineQuery, because throwing an
1264  * error between those steps would result in leaking our plancache
1265  * refcount.)
1266  */
1267  if (read_only || IsInParallelMode())
1268  {
1269  ListCell *lc;
1270 
1271  foreach(lc, stmt_list)
1272  {
1273  PlannedStmt *pstmt = castNode(PlannedStmt, lfirst(lc));
1274 
1275  if (!CommandIsReadOnly(pstmt))
1276  {
1277  if (read_only)
1278  ereport(ERROR,
1279  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1280  /* translator: %s is a SQL statement name */
1281  errmsg("%s is not allowed in a non-volatile function",
1282  CreateCommandTag((Node *) pstmt))));
1283  else
1285  }
1286  }
1287  }
1288 
1289  /* Set up the snapshot to use. */
1290  if (read_only)
1291  snapshot = GetActiveSnapshot();
1292  else
1293  {
1295  snapshot = GetTransactionSnapshot();
1296  }
1297 
1298  /*
1299  * If the plan has parameters, copy them into the portal. Note that this
1300  * must be done after revalidating the plan, because in dynamic parameter
1301  * cases the set of parameters could have changed during re-parsing.
1302  */
1303  if (paramLI)
1304  {
1305  oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
1306  paramLI = copyParamList(paramLI);
1307  MemoryContextSwitchTo(oldcontext);
1308  }
1309 
1310  /*
1311  * Start portal execution.
1312  */
1313  PortalStart(portal, paramLI, 0, snapshot);
1314 
1315  Assert(portal->strategy != PORTAL_MULTI_QUERY);
1316 
1317  /* Pop the SPI stack */
1318  _SPI_end_call(true);
1319 
1320  /* Return the created portal */
1321  return portal;
1322 }
1323 
1324 
1325 /*
1326  * SPI_cursor_find()
1327  *
1328  * Find the portal of an existing open cursor
1329  */
1330 Portal
1331 SPI_cursor_find(const char *name)
1332 {
1333  return GetPortalByName(name);
1334 }
1335 
1336 
1337 /*
1338  * SPI_cursor_fetch()
1339  *
1340  * Fetch rows in a cursor
1341  */
1342 void
1343 SPI_cursor_fetch(Portal portal, bool forward, long count)
1344 {
1345  _SPI_cursor_operation(portal,
1346  forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1348  /* we know that the DestSPI receiver doesn't need a destroy call */
1349 }
1350 
1351 
1352 /*
1353  * SPI_cursor_move()
1354  *
1355  * Move in a cursor
1356  */
1357 void
1358 SPI_cursor_move(Portal portal, bool forward, long count)
1359 {
1360  _SPI_cursor_operation(portal,
1361  forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
1362  None_Receiver);
1363 }
1364 
1365 
1366 /*
1367  * SPI_scroll_cursor_fetch()
1368  *
1369  * Fetch rows in a scrollable cursor
1370  */
1371 void
1372 SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count)
1373 {
1374  _SPI_cursor_operation(portal,
1375  direction, count,
1377  /* we know that the DestSPI receiver doesn't need a destroy call */
1378 }
1379 
1380 
1381 /*
1382  * SPI_scroll_cursor_move()
1383  *
1384  * Move in a scrollable cursor
1385  */
1386 void
1387 SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count)
1388 {
1389  _SPI_cursor_operation(portal, direction, count, None_Receiver);
1390 }
1391 
1392 
1393 /*
1394  * SPI_cursor_close()
1395  *
1396  * Close a cursor
1397  */
1398 void
1400 {
1401  if (!PortalIsValid(portal))
1402  elog(ERROR, "invalid portal in SPI cursor operation");
1403 
1404  PortalDrop(portal, false);
1405 }
1406 
1407 /*
1408  * Returns the Oid representing the type id for argument at argIndex. First
1409  * parameter is at index zero.
1410  */
1411 Oid
1412 SPI_getargtypeid(SPIPlanPtr plan, int argIndex)
1413 {
1414  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
1415  argIndex < 0 || argIndex >= plan->nargs)
1416  {
1418  return InvalidOid;
1419  }
1420  return plan->argtypes[argIndex];
1421 }
1422 
1423 /*
1424  * Returns the number of arguments for the prepared plan.
1425  */
1426 int
1428 {
1429  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1430  {
1432  return -1;
1433  }
1434  return plan->nargs;
1435 }
1436 
1437 /*
1438  * Returns true if the plan contains exactly one command
1439  * and that command returns tuples to the caller (eg, SELECT or
1440  * INSERT ... RETURNING, but not SELECT ... INTO). In essence,
1441  * the result indicates if the command can be used with SPI_cursor_open
1442  *
1443  * Parameters
1444  * plan: A plan previously prepared using SPI_prepare
1445  */
1446 bool
1448 {
1449  CachedPlanSource *plansource;
1450 
1451  if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
1452  {
1454  return false;
1455  }
1456 
1457  if (list_length(plan->plancache_list) != 1)
1458  {
1459  SPI_result = 0;
1460  return false; /* not exactly 1 pre-rewrite command */
1461  }
1462  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1463 
1464  /*
1465  * We used to force revalidation of the cached plan here, but that seems
1466  * unnecessary: invalidation could mean a change in the rowtype of the
1467  * tuples returned by a plan, but not whether it returns tuples at all.
1468  */
1469  SPI_result = 0;
1470 
1471  /* Does it return tuples? */
1472  if (plansource->resultDesc)
1473  return true;
1474 
1475  return false;
1476 }
1477 
1478 /*
1479  * SPI_plan_is_valid --- test whether a SPI plan is currently valid
1480  * (that is, not marked as being in need of revalidation).
1481  *
1482  * See notes for CachedPlanIsValid before using this.
1483  */
1484 bool
1486 {
1487  ListCell *lc;
1488 
1489  Assert(plan->magic == _SPI_PLAN_MAGIC);
1490 
1491  foreach(lc, plan->plancache_list)
1492  {
1493  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
1494 
1495  if (!CachedPlanIsValid(plansource))
1496  return false;
1497  }
1498  return true;
1499 }
1500 
1501 /*
1502  * SPI_result_code_string --- convert any SPI return code to a string
1503  *
1504  * This is often useful in error messages. Most callers will probably
1505  * only pass negative (error-case) codes, but for generality we recognize
1506  * the success codes too.
1507  */
1508 const char *
1510 {
1511  static char buf[64];
1512 
1513  switch (code)
1514  {
1515  case SPI_ERROR_CONNECT:
1516  return "SPI_ERROR_CONNECT";
1517  case SPI_ERROR_COPY:
1518  return "SPI_ERROR_COPY";
1519  case SPI_ERROR_OPUNKNOWN:
1520  return "SPI_ERROR_OPUNKNOWN";
1521  case SPI_ERROR_UNCONNECTED:
1522  return "SPI_ERROR_UNCONNECTED";
1523  case SPI_ERROR_ARGUMENT:
1524  return "SPI_ERROR_ARGUMENT";
1525  case SPI_ERROR_PARAM:
1526  return "SPI_ERROR_PARAM";
1527  case SPI_ERROR_TRANSACTION:
1528  return "SPI_ERROR_TRANSACTION";
1529  case SPI_ERROR_NOATTRIBUTE:
1530  return "SPI_ERROR_NOATTRIBUTE";
1531  case SPI_ERROR_NOOUTFUNC:
1532  return "SPI_ERROR_NOOUTFUNC";
1533  case SPI_ERROR_TYPUNKNOWN:
1534  return "SPI_ERROR_TYPUNKNOWN";
1535  case SPI_OK_CONNECT:
1536  return "SPI_OK_CONNECT";
1537  case SPI_OK_FINISH:
1538  return "SPI_OK_FINISH";
1539  case SPI_OK_FETCH:
1540  return "SPI_OK_FETCH";
1541  case SPI_OK_UTILITY:
1542  return "SPI_OK_UTILITY";
1543  case SPI_OK_SELECT:
1544  return "SPI_OK_SELECT";
1545  case SPI_OK_SELINTO:
1546  return "SPI_OK_SELINTO";
1547  case SPI_OK_INSERT:
1548  return "SPI_OK_INSERT";
1549  case SPI_OK_DELETE:
1550  return "SPI_OK_DELETE";
1551  case SPI_OK_UPDATE:
1552  return "SPI_OK_UPDATE";
1553  case SPI_OK_CURSOR:
1554  return "SPI_OK_CURSOR";
1556  return "SPI_OK_INSERT_RETURNING";
1558  return "SPI_OK_DELETE_RETURNING";
1560  return "SPI_OK_UPDATE_RETURNING";
1561  case SPI_OK_REWRITTEN:
1562  return "SPI_OK_REWRITTEN";
1563  }
1564  /* Unrecognized code ... return something useful ... */
1565  sprintf(buf, "Unrecognized SPI code %d", code);
1566  return buf;
1567 }
1568 
1569 /*
1570  * SPI_plan_get_plan_sources --- get a SPI plan's underlying list of
1571  * CachedPlanSources.
1572  *
1573  * This is exported so that pl/pgsql can use it (this beats letting pl/pgsql
1574  * look directly into the SPIPlan for itself). It's not documented in
1575  * spi.sgml because we'd just as soon not have too many places using this.
1576  */
1577 List *
1579 {
1580  Assert(plan->magic == _SPI_PLAN_MAGIC);
1581  return plan->plancache_list;
1582 }
1583 
1584 /*
1585  * SPI_plan_get_cached_plan --- get a SPI plan's generic CachedPlan,
1586  * if the SPI plan contains exactly one CachedPlanSource. If not,
1587  * return NULL. Caller is responsible for doing ReleaseCachedPlan().
1588  *
1589  * This is exported so that pl/pgsql can use it (this beats letting pl/pgsql
1590  * look directly into the SPIPlan for itself). It's not documented in
1591  * spi.sgml because we'd just as soon not have too many places using this.
1592  */
1593 CachedPlan *
1595 {
1596  CachedPlanSource *plansource;
1597  CachedPlan *cplan;
1598  ErrorContextCallback spierrcontext;
1599 
1600  Assert(plan->magic == _SPI_PLAN_MAGIC);
1601 
1602  /* Can't support one-shot plans here */
1603  if (plan->oneshot)
1604  return NULL;
1605 
1606  /* Must have exactly one CachedPlanSource */
1607  if (list_length(plan->plancache_list) != 1)
1608  return NULL;
1609  plansource = (CachedPlanSource *) linitial(plan->plancache_list);
1610 
1611  /* Setup error traceback support for ereport() */
1612  spierrcontext.callback = _SPI_error_callback;
1613  spierrcontext.arg = (void *) plansource->query_string;
1614  spierrcontext.previous = error_context_stack;
1615  error_context_stack = &spierrcontext;
1616 
1617  /* Get the generic plan for the query */
1618  cplan = GetCachedPlan(plansource, NULL, plan->saved);
1619  Assert(cplan == plansource->gplan);
1620 
1621  /* Pop the error context stack */
1622  error_context_stack = spierrcontext.previous;
1623 
1624  return cplan;
1625 }
1626 
1627 
1628 /* =================== private functions =================== */
1629 
1630 /*
1631  * spi_dest_startup
1632  * Initialize to receive tuples from Executor into SPITupleTable
1633  * of current SPI procedure
1634  */
1635 void
1636 spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
1637 {
1638  SPITupleTable *tuptable;
1639  MemoryContext oldcxt;
1640  MemoryContext tuptabcxt;
1641 
1642  if (_SPI_current == NULL)
1643  elog(ERROR, "spi_dest_startup called while not connected to SPI");
1644 
1645  if (_SPI_current->tuptable != NULL)
1646  elog(ERROR, "improper call to spi_dest_startup");
1647 
1648  /* We create the tuple table context as a child of procCxt */
1649 
1650  oldcxt = _SPI_procmem(); /* switch to procedure memory context */
1651 
1653  "SPI TupTable",
1655  MemoryContextSwitchTo(tuptabcxt);
1656 
1657  _SPI_current->tuptable = tuptable = (SPITupleTable *)
1658  palloc0(sizeof(SPITupleTable));
1659  tuptable->tuptabcxt = tuptabcxt;
1660  tuptable->subid = GetCurrentSubTransactionId();
1661 
1662  /*
1663  * The tuptable is now valid enough to be freed by AtEOSubXact_SPI, so put
1664  * it onto the SPI context's tuptables list. This will ensure it's not
1665  * leaked even in the unlikely event the following few lines fail.
1666  */
1667  slist_push_head(&_SPI_current->tuptables, &tuptable->next);
1668 
1669  /* set up initial allocations */
1670  tuptable->alloced = tuptable->free = 128;
1671  tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
1672  tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
1673 
1674  MemoryContextSwitchTo(oldcxt);
1675 }
1676 
1677 /*
1678  * spi_printtup
1679  * store tuple retrieved by Executor into SPITupleTable
1680  * of current SPI procedure
1681  */
1682 bool
1684 {
1685  SPITupleTable *tuptable;
1686  MemoryContext oldcxt;
1687 
1688  if (_SPI_current == NULL)
1689  elog(ERROR, "spi_printtup called while not connected to SPI");
1690 
1691  tuptable = _SPI_current->tuptable;
1692  if (tuptable == NULL)
1693  elog(ERROR, "improper call to spi_printtup");
1694 
1695  oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
1696 
1697  if (tuptable->free == 0)
1698  {
1699  /* Double the size of the pointer array */
1700  tuptable->free = tuptable->alloced;
1701  tuptable->alloced += tuptable->free;
1702  tuptable->vals = (HeapTuple *) repalloc_huge(tuptable->vals,
1703  tuptable->alloced * sizeof(HeapTuple));
1704  }
1705 
1706  tuptable->vals[tuptable->alloced - tuptable->free] =
1707  ExecCopySlotTuple(slot);
1708  (tuptable->free)--;
1709 
1710  MemoryContextSwitchTo(oldcxt);
1711 
1712  return true;
1713 }
1714 
1715 /*
1716  * Static functions
1717  */
1718 
1719 /*
1720  * Parse and analyze a querystring.
1721  *
1722  * At entry, plan->argtypes and plan->nargs (or alternatively plan->parserSetup
1723  * and plan->parserSetupArg) must be valid, as must plan->cursor_options.
1724  *
1725  * Results are stored into *plan (specifically, plan->plancache_list).
1726  * Note that the result data is all in CurrentMemoryContext or child contexts
1727  * thereof; in practice this means it is in the SPI executor context, and
1728  * what we are creating is a "temporary" SPIPlan. Cruft generated during
1729  * parsing is also left in CurrentMemoryContext.
1730  */
1731 static void
1732 _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
1733 {
1734  List *raw_parsetree_list;
1735  List *plancache_list;
1736  ListCell *list_item;
1737  ErrorContextCallback spierrcontext;
1738 
1739  /*
1740  * Setup error traceback support for ereport()
1741  */
1742  spierrcontext.callback = _SPI_error_callback;
1743  spierrcontext.arg = (void *) src;
1744  spierrcontext.previous = error_context_stack;
1745  error_context_stack = &spierrcontext;
1746 
1747  /*
1748  * Parse the request string into a list of raw parse trees.
1749  */
1750  raw_parsetree_list = pg_parse_query(src);
1751 
1752  /*
1753  * Do parse analysis and rule rewrite for each raw parsetree, storing the
1754  * results into unsaved plancache entries.
1755  */
1756  plancache_list = NIL;
1757 
1758  foreach(list_item, raw_parsetree_list)
1759  {
1760  RawStmt *parsetree = castNode(RawStmt, lfirst(list_item));
1761  List *stmt_list;
1762  CachedPlanSource *plansource;
1763 
1764  /*
1765  * Create the CachedPlanSource before we do parse analysis, since it
1766  * needs to see the unmodified raw parse tree.
1767  */
1768  plansource = CreateCachedPlan(parsetree,
1769  src,
1770  CreateCommandTag(parsetree->stmt));
1771 
1772  /*
1773  * Parameter datatypes are driven by parserSetup hook if provided,
1774  * otherwise we use the fixed parameter list.
1775  */
1776  if (plan->parserSetup != NULL)
1777  {
1778  Assert(plan->nargs == 0);
1779  stmt_list = pg_analyze_and_rewrite_params(parsetree,
1780  src,
1781  plan->parserSetup,
1782  plan->parserSetupArg);
1783  }
1784  else
1785  {
1786  stmt_list = pg_analyze_and_rewrite(parsetree,
1787  src,
1788  plan->argtypes,
1789  plan->nargs);
1790  }
1791 
1792  /* Finish filling in the CachedPlanSource */
1793  CompleteCachedPlan(plansource,
1794  stmt_list,
1795  NULL,
1796  plan->argtypes,
1797  plan->nargs,
1798  plan->parserSetup,
1799  plan->parserSetupArg,
1800  plan->cursor_options,
1801  false); /* not fixed result */
1802 
1803  plancache_list = lappend(plancache_list, plansource);
1804  }
1805 
1806  plan->plancache_list = plancache_list;
1807  plan->oneshot = false;
1808 
1809  /*
1810  * Pop the error context stack
1811  */
1812  error_context_stack = spierrcontext.previous;
1813 }
1814 
1815 /*
1816  * Parse, but don't analyze, a querystring.
1817  *
1818  * This is a stripped-down version of _SPI_prepare_plan that only does the
1819  * initial raw parsing. It creates "one shot" CachedPlanSources
1820  * that still require parse analysis before execution is possible.
1821  *
1822  * The advantage of using the "one shot" form of CachedPlanSource is that
1823  * we eliminate data copying and invalidation overhead. Postponing parse
1824  * analysis also prevents issues if some of the raw parsetrees are DDL
1825  * commands that affect validity of later parsetrees. Both of these
1826  * attributes are good things for SPI_execute() and similar cases.
1827  *
1828  * Results are stored into *plan (specifically, plan->plancache_list).
1829  * Note that the result data is all in CurrentMemoryContext or child contexts
1830  * thereof; in practice this means it is in the SPI executor context, and
1831  * what we are creating is a "temporary" SPIPlan. Cruft generated during
1832  * parsing is also left in CurrentMemoryContext.
1833  */
1834 static void
1836 {
1837  List *raw_parsetree_list;
1838  List *plancache_list;
1839  ListCell *list_item;
1840  ErrorContextCallback spierrcontext;
1841 
1842  /*
1843  * Setup error traceback support for ereport()
1844  */
1845  spierrcontext.callback = _SPI_error_callback;
1846  spierrcontext.arg = (void *) src;
1847  spierrcontext.previous = error_context_stack;
1848  error_context_stack = &spierrcontext;
1849 
1850  /*
1851  * Parse the request string into a list of raw parse trees.
1852  */
1853  raw_parsetree_list = pg_parse_query(src);
1854 
1855  /*
1856  * Construct plancache entries, but don't do parse analysis yet.
1857  */
1858  plancache_list = NIL;
1859 
1860  foreach(list_item, raw_parsetree_list)
1861  {
1862  RawStmt *parsetree = castNode(RawStmt, lfirst(list_item));
1863  CachedPlanSource *plansource;
1864 
1865  plansource = CreateOneShotCachedPlan(parsetree,
1866  src,
1867  CreateCommandTag(parsetree->stmt));
1868 
1869  plancache_list = lappend(plancache_list, plansource);
1870  }
1871 
1872  plan->plancache_list = plancache_list;
1873  plan->oneshot = true;
1874 
1875  /*
1876  * Pop the error context stack
1877  */
1878  error_context_stack = spierrcontext.previous;
1879 }
1880 
1881 /*
1882  * Execute the given plan with the given parameter values
1883  *
1884  * snapshot: query snapshot to use, or InvalidSnapshot for the normal
1885  * behavior of taking a new snapshot for each query.
1886  * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
1887  * read_only: TRUE for read-only execution (no CommandCounterIncrement)
1888  * fire_triggers: TRUE to fire AFTER triggers at end of query (normal case);
1889  * FALSE means any AFTER triggers are postponed to end of outer query
1890  * tcount: execution tuple-count limit, or 0 for none
1891  */
1892 static int
1894  Snapshot snapshot, Snapshot crosscheck_snapshot,
1895  bool read_only, bool fire_triggers, uint64 tcount)
1896 {
1897  int my_res = 0;
1898  uint64 my_processed = 0;
1899  Oid my_lastoid = InvalidOid;
1900  SPITupleTable *my_tuptable = NULL;
1901  int res = 0;
1902  bool pushed_active_snap = false;
1903  ErrorContextCallback spierrcontext;
1904  CachedPlan *cplan = NULL;
1905  ListCell *lc1;
1906 
1907  /*
1908  * Setup error traceback support for ereport()
1909  */
1910  spierrcontext.callback = _SPI_error_callback;
1911  spierrcontext.arg = NULL; /* we'll fill this below */
1912  spierrcontext.previous = error_context_stack;
1913  error_context_stack = &spierrcontext;
1914 
1915  /*
1916  * We support four distinct snapshot management behaviors:
1917  *
1918  * snapshot != InvalidSnapshot, read_only = true: use exactly the given
1919  * snapshot.
1920  *
1921  * snapshot != InvalidSnapshot, read_only = false: use the given snapshot,
1922  * modified by advancing its command ID before each querytree.
1923  *
1924  * snapshot == InvalidSnapshot, read_only = true: use the entry-time
1925  * ActiveSnapshot, if any (if there isn't one, we run with no snapshot).
1926  *
1927  * snapshot == InvalidSnapshot, read_only = false: take a full new
1928  * snapshot for each user command, and advance its command ID before each
1929  * querytree within the command.
1930  *
1931  * In the first two cases, we can just push the snap onto the stack once
1932  * for the whole plan list.
1933  */
1934  if (snapshot != InvalidSnapshot)
1935  {
1936  if (read_only)
1937  {
1938  PushActiveSnapshot(snapshot);
1939  pushed_active_snap = true;
1940  }
1941  else
1942  {
1943  /* Make sure we have a private copy of the snapshot to modify */
1944  PushCopiedSnapshot(snapshot);
1945  pushed_active_snap = true;
1946  }
1947  }
1948 
1949  foreach(lc1, plan->plancache_list)
1950  {
1951  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
1952  List *stmt_list;
1953  ListCell *lc2;
1954 
1955  spierrcontext.arg = (void *) plansource->query_string;
1956 
1957  /*
1958  * If this is a one-shot plan, we still need to do parse analysis.
1959  */
1960  if (plan->oneshot)
1961  {
1962  RawStmt *parsetree = plansource->raw_parse_tree;
1963  const char *src = plansource->query_string;
1964  List *stmt_list;
1965 
1966  /*
1967  * Parameter datatypes are driven by parserSetup hook if provided,
1968  * otherwise we use the fixed parameter list.
1969  */
1970  if (parsetree == NULL)
1971  stmt_list = NIL;
1972  else if (plan->parserSetup != NULL)
1973  {
1974  Assert(plan->nargs == 0);
1975  stmt_list = pg_analyze_and_rewrite_params(parsetree,
1976  src,
1977  plan->parserSetup,
1978  plan->parserSetupArg);
1979  }
1980  else
1981  {
1982  stmt_list = pg_analyze_and_rewrite(parsetree,
1983  src,
1984  plan->argtypes,
1985  plan->nargs);
1986  }
1987 
1988  /* Finish filling in the CachedPlanSource */
1989  CompleteCachedPlan(plansource,
1990  stmt_list,
1991  NULL,
1992  plan->argtypes,
1993  plan->nargs,
1994  plan->parserSetup,
1995  plan->parserSetupArg,
1996  plan->cursor_options,
1997  false); /* not fixed result */
1998  }
1999 
2000  /*
2001  * Replan if needed, and increment plan refcount. If it's a saved
2002  * plan, the refcount must be backed by the CurrentResourceOwner.
2003  */
2004  cplan = GetCachedPlan(plansource, paramLI, plan->saved);
2005  stmt_list = cplan->stmt_list;
2006 
2007  /*
2008  * In the default non-read-only case, get a new snapshot, replacing
2009  * any that we pushed in a previous cycle.
2010  */
2011  if (snapshot == InvalidSnapshot && !read_only)
2012  {
2013  if (pushed_active_snap)
2016  pushed_active_snap = true;
2017  }
2018 
2019  foreach(lc2, stmt_list)
2020  {
2021  PlannedStmt *stmt = castNode(PlannedStmt, lfirst(lc2));
2022  bool canSetTag = stmt->canSetTag;
2023  DestReceiver *dest;
2024 
2025  _SPI_current->processed = 0;
2026  _SPI_current->lastoid = InvalidOid;
2027  _SPI_current->tuptable = NULL;
2028 
2029  if (stmt->utilityStmt)
2030  {
2031  if (IsA(stmt->utilityStmt, CopyStmt))
2032  {
2033  CopyStmt *cstmt = (CopyStmt *) stmt->utilityStmt;
2034 
2035  if (cstmt->filename == NULL)
2036  {
2037  my_res = SPI_ERROR_COPY;
2038  goto fail;
2039  }
2040  }
2041  else if (IsA(stmt->utilityStmt, TransactionStmt))
2042  {
2043  my_res = SPI_ERROR_TRANSACTION;
2044  goto fail;
2045  }
2046  }
2047 
2048  if (read_only && !CommandIsReadOnly(stmt))
2049  ereport(ERROR,
2050  (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2051  /* translator: %s is a SQL statement name */
2052  errmsg("%s is not allowed in a non-volatile function",
2053  CreateCommandTag((Node *) stmt))));
2054 
2055  if (IsInParallelMode() && !CommandIsReadOnly(stmt))
2057 
2058  /*
2059  * If not read-only mode, advance the command counter before each
2060  * command and update the snapshot.
2061  */
2062  if (!read_only)
2063  {
2066  }
2067 
2068  dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone);
2069 
2070  if (stmt->utilityStmt == NULL)
2071  {
2072  QueryDesc *qdesc;
2073  Snapshot snap;
2074 
2075  if (ActiveSnapshotSet())
2076  snap = GetActiveSnapshot();
2077  else
2078  snap = InvalidSnapshot;
2079 
2080  qdesc = CreateQueryDesc(stmt,
2081  plansource->query_string,
2082  snap, crosscheck_snapshot,
2083  dest,
2084  paramLI, 0);
2085  res = _SPI_pquery(qdesc, fire_triggers,
2086  canSetTag ? tcount : 0);
2087  FreeQueryDesc(qdesc);
2088  }
2089  else
2090  {
2091  char completionTag[COMPLETION_TAG_BUFSIZE];
2092 
2093  ProcessUtility(stmt,
2094  plansource->query_string,
2096  paramLI,
2097  dest,
2098  completionTag);
2099 
2100  /* Update "processed" if stmt returned tuples */
2101  if (_SPI_current->tuptable)
2102  _SPI_current->processed = _SPI_current->tuptable->alloced -
2103  _SPI_current->tuptable->free;
2104 
2105  res = SPI_OK_UTILITY;
2106 
2107  /*
2108  * Some utility statements return a row count, even though the
2109  * tuples are not returned to the caller.
2110  */
2111  if (IsA(stmt->utilityStmt, CreateTableAsStmt))
2112  {
2113  CreateTableAsStmt *ctastmt = (CreateTableAsStmt *) stmt->utilityStmt;
2114 
2115  if (strncmp(completionTag, "SELECT ", 7) == 0)
2116  _SPI_current->processed =
2117  pg_strtouint64(completionTag + 7, NULL, 10);
2118  else
2119  {
2120  /*
2121  * Must be an IF NOT EXISTS that did nothing, or a
2122  * CREATE ... WITH NO DATA.
2123  */
2124  Assert(ctastmt->if_not_exists ||
2125  ctastmt->into->skipData);
2126  _SPI_current->processed = 0;
2127  }
2128 
2129  /*
2130  * For historical reasons, if CREATE TABLE AS was spelled
2131  * as SELECT INTO, return a special return code.
2132  */
2133  if (ctastmt->is_select_into)
2134  res = SPI_OK_SELINTO;
2135  }
2136  else if (IsA(stmt->utilityStmt, CopyStmt))
2137  {
2138  Assert(strncmp(completionTag, "COPY ", 5) == 0);
2139  _SPI_current->processed = pg_strtouint64(completionTag + 5,
2140  NULL, 10);
2141  }
2142  }
2143 
2144  /*
2145  * The last canSetTag query sets the status values returned to the
2146  * caller. Be careful to free any tuptables not returned, to
2147  * avoid intratransaction memory leak.
2148  */
2149  if (canSetTag)
2150  {
2151  my_processed = _SPI_current->processed;
2152  my_lastoid = _SPI_current->lastoid;
2153  SPI_freetuptable(my_tuptable);
2154  my_tuptable = _SPI_current->tuptable;
2155  my_res = res;
2156  }
2157  else
2158  {
2159  SPI_freetuptable(_SPI_current->tuptable);
2160  _SPI_current->tuptable = NULL;
2161  }
2162  /* we know that the receiver doesn't need a destroy call */
2163  if (res < 0)
2164  {
2165  my_res = res;
2166  goto fail;
2167  }
2168  }
2169 
2170  /* Done with this plan, so release refcount */
2171  ReleaseCachedPlan(cplan, plan->saved);
2172  cplan = NULL;
2173 
2174  /*
2175  * If not read-only mode, advance the command counter after the last
2176  * command. This ensures that its effects are visible, in case it was
2177  * DDL that would affect the next CachedPlanSource.
2178  */
2179  if (!read_only)
2181  }
2182 
2183 fail:
2184 
2185  /* Pop the snapshot off the stack if we pushed one */
2186  if (pushed_active_snap)
2188 
2189  /* We no longer need the cached plan refcount, if any */
2190  if (cplan)
2191  ReleaseCachedPlan(cplan, plan->saved);
2192 
2193  /*
2194  * Pop the error context stack
2195  */
2196  error_context_stack = spierrcontext.previous;
2197 
2198  /* Save results for caller */
2199  SPI_processed = my_processed;
2200  SPI_lastoid = my_lastoid;
2201  SPI_tuptable = my_tuptable;
2202 
2203  /* tuptable now is caller's responsibility, not SPI's */
2204  _SPI_current->tuptable = NULL;
2205 
2206  /*
2207  * If none of the queries had canSetTag, return SPI_OK_REWRITTEN. Prior to
2208  * 8.4, we used return the last query's result code, but not its auxiliary
2209  * results, but that's confusing.
2210  */
2211  if (my_res == 0)
2212  my_res = SPI_OK_REWRITTEN;
2213 
2214  return my_res;
2215 }
2216 
2217 /*
2218  * Convert arrays of query parameters to form wanted by planner and executor
2219  */
2220 static ParamListInfo
2221 _SPI_convert_params(int nargs, Oid *argtypes,
2222  Datum *Values, const char *Nulls)
2223 {
2224  ParamListInfo paramLI;
2225 
2226  if (nargs > 0)
2227  {
2228  int i;
2229 
2230  paramLI = (ParamListInfo) palloc(offsetof(ParamListInfoData, params) +
2231  nargs * sizeof(ParamExternData));
2232  /* we have static list of params, so no hooks needed */
2233  paramLI->paramFetch = NULL;
2234  paramLI->paramFetchArg = NULL;
2235  paramLI->parserSetup = NULL;
2236  paramLI->parserSetupArg = NULL;
2237  paramLI->numParams = nargs;
2238  paramLI->paramMask = NULL;
2239 
2240  for (i = 0; i < nargs; i++)
2241  {
2242  ParamExternData *prm = &paramLI->params[i];
2243 
2244  prm->value = Values[i];
2245  prm->isnull = (Nulls && Nulls[i] == 'n');
2246  prm->pflags = PARAM_FLAG_CONST;
2247  prm->ptype = argtypes[i];
2248  }
2249  }
2250  else
2251  paramLI = NULL;
2252  return paramLI;
2253 }
2254 
2255 static int
2256 _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
2257 {
2258  int operation = queryDesc->operation;
2259  int eflags;
2260  int res;
2261 
2262  switch (operation)
2263  {
2264  case CMD_SELECT:
2265  if (queryDesc->dest->mydest != DestSPI)
2266  {
2267  /* Don't return SPI_OK_SELECT if we're discarding result */
2268  res = SPI_OK_UTILITY;
2269  }
2270  else
2271  res = SPI_OK_SELECT;
2272  break;
2273  case CMD_INSERT:
2274  if (queryDesc->plannedstmt->hasReturning)
2276  else
2277  res = SPI_OK_INSERT;
2278  break;
2279  case CMD_DELETE:
2280  if (queryDesc->plannedstmt->hasReturning)
2282  else
2283  res = SPI_OK_DELETE;
2284  break;
2285  case CMD_UPDATE:
2286  if (queryDesc->plannedstmt->hasReturning)
2288  else
2289  res = SPI_OK_UPDATE;
2290  break;
2291  default:
2292  return SPI_ERROR_OPUNKNOWN;
2293  }
2294 
2295 #ifdef SPI_EXECUTOR_STATS
2296  if (ShowExecutorStats)
2297  ResetUsage();
2298 #endif
2299 
2300  /* Select execution options */
2301  if (fire_triggers)
2302  eflags = 0; /* default run-to-completion flags */
2303  else
2304  eflags = EXEC_FLAG_SKIP_TRIGGERS;
2305 
2306  ExecutorStart(queryDesc, eflags);
2307 
2308  ExecutorRun(queryDesc, ForwardScanDirection, tcount);
2309 
2310  _SPI_current->processed = queryDesc->estate->es_processed;
2311  _SPI_current->lastoid = queryDesc->estate->es_lastoid;
2312 
2313  if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->hasReturning) &&
2314  queryDesc->dest->mydest == DestSPI)
2315  {
2316  if (_SPI_checktuples())
2317  elog(ERROR, "consistency check on SPI tuple count failed");
2318  }
2319 
2320  ExecutorFinish(queryDesc);
2321  ExecutorEnd(queryDesc);
2322  /* FreeQueryDesc is done by the caller */
2323 
2324 #ifdef SPI_EXECUTOR_STATS
2325  if (ShowExecutorStats)
2326  ShowUsage("SPI EXECUTOR STATS");
2327 #endif
2328 
2329  return res;
2330 }
2331 
2332 /*
2333  * _SPI_error_callback
2334  *
2335  * Add context information when a query invoked via SPI fails
2336  */
2337 static void
2339 {
2340  const char *query = (const char *) arg;
2341  int syntaxerrposition;
2342 
2343  /*
2344  * If there is a syntax error position, convert to internal syntax error;
2345  * otherwise treat the query as an item of context stack
2346  */
2347  syntaxerrposition = geterrposition();
2348  if (syntaxerrposition > 0)
2349  {
2350  errposition(0);
2351  internalerrposition(syntaxerrposition);
2352  internalerrquery(query);
2353  }
2354  else
2355  errcontext("SQL statement \"%s\"", query);
2356 }
2357 
2358 /*
2359  * _SPI_cursor_operation()
2360  *
2361  * Do a FETCH or MOVE in a cursor
2362  */
2363 static void
2364 _SPI_cursor_operation(Portal portal, FetchDirection direction, long count,
2365  DestReceiver *dest)
2366 {
2367  uint64 nfetched;
2368 
2369  /* Check that the portal is valid */
2370  if (!PortalIsValid(portal))
2371  elog(ERROR, "invalid portal in SPI cursor operation");
2372 
2373  /* Push the SPI stack */
2374  if (_SPI_begin_call(true) < 0)
2375  elog(ERROR, "SPI cursor operation called while not connected");
2376 
2377  /* Reset the SPI result (note we deliberately don't touch lastoid) */
2378  SPI_processed = 0;
2379  SPI_tuptable = NULL;
2380  _SPI_current->processed = 0;
2381  _SPI_current->tuptable = NULL;
2382 
2383  /* Run the cursor */
2384  nfetched = PortalRunFetch(portal,
2385  direction,
2386  count,
2387  dest);
2388 
2389  /*
2390  * Think not to combine this store with the preceding function call. If
2391  * the portal contains calls to functions that use SPI, then SPI_stack is
2392  * likely to move around while the portal runs. When control returns,
2393  * _SPI_current will point to the correct stack entry... but the pointer
2394  * may be different than it was beforehand. So we must be sure to re-fetch
2395  * the pointer after the function call completes.
2396  */
2397  _SPI_current->processed = nfetched;
2398 
2399  if (dest->mydest == DestSPI && _SPI_checktuples())
2400  elog(ERROR, "consistency check on SPI tuple count failed");
2401 
2402  /* Put the result into place for access by caller */
2403  SPI_processed = _SPI_current->processed;
2404  SPI_tuptable = _SPI_current->tuptable;
2405 
2406  /* tuptable now is caller's responsibility, not SPI's */
2407  _SPI_current->tuptable = NULL;
2408 
2409  /* Pop the SPI stack */
2410  _SPI_end_call(true);
2411 }
2412 
2413 
2414 static MemoryContext
2416 {
2417  return MemoryContextSwitchTo(_SPI_current->execCxt);
2418 }
2419 
2420 static MemoryContext
2422 {
2423  return MemoryContextSwitchTo(_SPI_current->procCxt);
2424 }
2425 
2426 /*
2427  * _SPI_begin_call: begin a SPI operation within a connected procedure
2428  */
2429 static int
2430 _SPI_begin_call(bool execmem)
2431 {
2432  if (_SPI_current == NULL)
2433  return SPI_ERROR_UNCONNECTED;
2434 
2435  if (execmem) /* switch to the Executor memory context */
2436  _SPI_execmem();
2437 
2438  return 0;
2439 }
2440 
2441 /*
2442  * _SPI_end_call: end a SPI operation within a connected procedure
2443  *
2444  * Note: this currently has no failure return cases, so callers don't check
2445  */
2446 static int
2447 _SPI_end_call(bool procmem)
2448 {
2449  if (procmem) /* switch to the procedure memory context */
2450  {
2451  _SPI_procmem();
2452  /* and free Executor memory */
2454  }
2455 
2456  return 0;
2457 }
2458 
2459 static bool
2461 {
2462  uint64 processed = _SPI_current->processed;
2463  SPITupleTable *tuptable = _SPI_current->tuptable;
2464  bool failed = false;
2465 
2466  if (tuptable == NULL) /* spi_dest_startup was not called */
2467  failed = true;
2468  else if (processed != (tuptable->alloced - tuptable->free))
2469  failed = true;
2470 
2471  return failed;
2472 }
2473 
2474 /*
2475  * Convert a "temporary" SPIPlan into an "unsaved" plan.
2476  *
2477  * The passed _SPI_plan struct is on the stack, and all its subsidiary data
2478  * is in or under the current SPI executor context. Copy the plan into the
2479  * SPI procedure context so it will survive _SPI_end_call(). To minimize
2480  * data copying, this destructively modifies the input plan, by taking the
2481  * plancache entries away from it and reparenting them to the new SPIPlan.
2482  */
2483 static SPIPlanPtr
2485 {
2486  SPIPlanPtr newplan;
2487  MemoryContext parentcxt = _SPI_current->procCxt;
2488  MemoryContext plancxt;
2489  MemoryContext oldcxt;
2490  ListCell *lc;
2491 
2492  /* Assert the input is a temporary SPIPlan */
2493  Assert(plan->magic == _SPI_PLAN_MAGIC);
2494  Assert(plan->plancxt == NULL);
2495  /* One-shot plans can't be saved */
2496  Assert(!plan->oneshot);
2497 
2498  /*
2499  * Create a memory context for the plan, underneath the procedure context.
2500  * We don't expect the plan to be very large.
2501  */
2502  plancxt = AllocSetContextCreate(parentcxt,
2503  "SPI Plan",
2505  oldcxt = MemoryContextSwitchTo(plancxt);
2506 
2507  /* Copy the SPI_plan struct and subsidiary data into the new context */
2508  newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan));
2509  newplan->magic = _SPI_PLAN_MAGIC;
2510  newplan->saved = false;
2511  newplan->oneshot = false;
2512  newplan->plancache_list = NIL;
2513  newplan->plancxt = plancxt;
2514  newplan->cursor_options = plan->cursor_options;
2515  newplan->nargs = plan->nargs;
2516  if (plan->nargs > 0)
2517  {
2518  newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
2519  memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
2520  }
2521  else
2522  newplan->argtypes = NULL;
2523  newplan->parserSetup = plan->parserSetup;
2524  newplan->parserSetupArg = plan->parserSetupArg;
2525 
2526  /*
2527  * Reparent all the CachedPlanSources into the procedure context. In
2528  * theory this could fail partway through due to the pallocs, but we don't
2529  * care too much since both the procedure context and the executor context
2530  * would go away on error.
2531  */
2532  foreach(lc, plan->plancache_list)
2533  {
2534  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
2535 
2536  CachedPlanSetParentContext(plansource, parentcxt);
2537 
2538  /* Build new list, with list cells in plancxt */
2539  newplan->plancache_list = lappend(newplan->plancache_list, plansource);
2540  }
2541 
2542  MemoryContextSwitchTo(oldcxt);
2543 
2544  /* For safety, unlink the CachedPlanSources from the temporary plan */
2545  plan->plancache_list = NIL;
2546 
2547  return newplan;
2548 }
2549 
2550 /*
2551  * Make a "saved" copy of the given plan.
2552  */
2553 static SPIPlanPtr
2555 {
2556  SPIPlanPtr newplan;
2557  MemoryContext plancxt;
2558  MemoryContext oldcxt;
2559  ListCell *lc;
2560 
2561  /* One-shot plans can't be saved */
2562  Assert(!plan->oneshot);
2563 
2564  /*
2565  * Create a memory context for the plan. We don't expect the plan to be
2566  * very large, so use smaller-than-default alloc parameters. It's a
2567  * transient context until we finish copying everything.
2568  */
2570  "SPI Plan",
2572  oldcxt = MemoryContextSwitchTo(plancxt);
2573 
2574  /* Copy the SPI plan into its own context */
2575  newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan));
2576  newplan->magic = _SPI_PLAN_MAGIC;
2577  newplan->saved = false;
2578  newplan->oneshot = false;
2579  newplan->plancache_list = NIL;
2580  newplan->plancxt = plancxt;
2581  newplan->cursor_options = plan->cursor_options;
2582  newplan->nargs = plan->nargs;
2583  if (plan->nargs > 0)
2584  {
2585  newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
2586  memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
2587  }
2588  else
2589  newplan->argtypes = NULL;
2590  newplan->parserSetup = plan->parserSetup;
2591  newplan->parserSetupArg = plan->parserSetupArg;
2592 
2593  /* Copy all the plancache entries */
2594  foreach(lc, plan->plancache_list)
2595  {
2596  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
2597  CachedPlanSource *newsource;
2598 
2599  newsource = CopyCachedPlan(plansource);
2600  newplan->plancache_list = lappend(newplan->plancache_list, newsource);
2601  }
2602 
2603  MemoryContextSwitchTo(oldcxt);
2604 
2605  /*
2606  * Mark it saved, reparent it under CacheMemoryContext, and mark all the
2607  * component CachedPlanSources as saved. This sequence cannot fail
2608  * partway through, so there's no risk of long-term memory leakage.
2609  */
2610  newplan->saved = true;
2612 
2613  foreach(lc, newplan->plancache_list)
2614  {
2615  CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
2616 
2617  SaveCachedPlan(plansource);
2618  }
2619 
2620  return newplan;
2621 }
int SPI_fnumber(TupleDesc tupdesc, const char *fname)
Definition: spi.c:760
HeapTuple heap_copytuple(HeapTuple tuple)
Definition: heaptuple.c:608
static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:1732
ParamExternData params[FLEXIBLE_ARRAY_MEMBER]
Definition: params.h:76
ParamListInfo copyParamList(ParamListInfo from)
Definition: params.c:36
#define NIL
Definition: pg_list.h:69
Oid * argtypes
Definition: spi_priv.h:84
Datum value
Definition: params.h:56
#define SPI_OK_CONNECT
Definition: spi.h:47
bool CommandIsReadOnly(PlannedStmt *pstmt)
Definition: utility.c:96
static struct @76 value
Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber)
Definition: spi.c:891
Portal CreatePortal(const char *name, bool allowDup, bool dupSilent)
Definition: portalmem.c:174
TupleDesc CreateTupleDescCopy(TupleDesc tupdesc)
Definition: tupdesc.c:141
void UpdateActiveSnapshotCommandId(void)
Definition: snapmgr.c:776
#define IsA(nodeptr, _type_)
Definition: nodes.h:559
#define SPI_ERROR_PARAM
Definition: spi.h:41
void MemoryContextDelete(MemoryContext context)
Definition: mcxt.c:200
List * plancache_list
Definition: spi_priv.h:80
Oid tdtypeid
Definition: tupdesc.h:77
int errhint(const char *fmt,...)
Definition: elog.c:987
void getTypeOutputInfo(Oid type, Oid *typOutput, bool *typIsVarlena)
Definition: lsyscache.c:2600
#define GETSTRUCT(TUP)
Definition: htup_details.h:656
void * parserSetupArg
Definition: params.h:73
Portal CreateNewPortal(void)
Definition: portalmem.c:230
FetchDirection
Definition: parsenodes.h:2553
static int32 next
Definition: blutils.c:210
EState * estate
Definition: execdesc.h:47
MemoryContext TopTransactionContext
Definition: mcxt.c:48
HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
Definition: spi.c:657
bool tdhasoid
Definition: tupdesc.h:79
void PortalStart(Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
Definition: pquery.c:439
void SPI_freetuple(HeapTuple tuple)
Definition: spi.c:962
#define SPI_ERROR_UNCONNECTED
Definition: spi.h:38
void PreventCommandIfParallelMode(const char *cmdname)
Definition: utility.c:253
CachedPlanSource * CreateOneShotCachedPlan(RawStmt *raw_parse_tree, const char *query_string, const char *commandTag)
Definition: plancache.c:234
void PortalDefineQuery(Portal portal, const char *prepStmtName, const char *sourceText, const char *commandTag, List *stmts, CachedPlan *cplan)
Definition: portalmem.c:277
Oid es_lastoid
Definition: execnodes.h:404
bool SPI_is_cursor_plan(SPIPlanPtr plan)
Definition: spi.c:1447
int SPI_connect(void)
Definition: spi.c:84
#define _SPI_PLAN_MAGIC
Definition: spi_priv.h:19
#define SPI_OK_DELETE_RETURNING
Definition: spi.h:58
#define castNode(_type_, nodeptr)
Definition: nodes.h:577
void FreeQueryDesc(QueryDesc *qdesc)
Definition: pquery.c:100
const char * commandTag
Definition: plancache.h:84
static int _SPI_stack_depth
Definition: spi.c:46
void SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count)
Definition: spi.c:1372
Definition: dest.h:93
void ShowUsage(const char *title)
Definition: postgres.c:4383
void MemoryContextSetParent(MemoryContext context, MemoryContext new_parent)
Definition: mcxt.c:317
Portal GetPortalByName(const char *name)
Definition: portalmem.c:129
int magic
Definition: spi_priv.h:77
#define SPI_OK_DELETE
Definition: spi.h:54
CommandDest mydest
Definition: dest.h:128
char * pstrdup(const char *in)
Definition: mcxt.c:1165
SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes)
Definition: spi.c:481
Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan, ParamListInfo params, bool read_only)
Definition: spi.c:1107
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:155
slist_node * cur
Definition: ilist.h:241
int SPI_finish(void)
Definition: spi.c:147
uint64 PortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
Definition: pquery.c:1379
void SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count)
Definition: spi.c:1387
SPIPlanPtr SPI_saveplan(SPIPlanPtr plan)
Definition: spi.c:586
void ExecutorStart(QueryDesc *queryDesc, int eflags)
Definition: execMain.c:138
#define SPI_ERROR_COPY
Definition: spi.h:36
Form_pg_attribute * attrs
Definition: tupdesc.h:74
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
Snapshot GetActiveSnapshot(void)
Definition: snapmgr.c:834
Form_pg_attribute SystemAttributeByName(const char *attname, bool relhasoids)
Definition: heap.c:212
static void slist_push_head(slist_head *head, slist_node *node)
Definition: ilist.h:574
void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
Definition: spi.c:214
SPITupleTable * SPI_tuptable
Definition: spi.c:41
Definition: nodes.h:508
void ExecutorRun(QueryDesc *queryDesc, ScanDirection direction, uint64 count)
Definition: execMain.c:285
slist_node next
Definition: spi.h:28
#define SPI_ERROR_OPUNKNOWN
Definition: spi.h:37
int errcode(int sqlerrcode)
Definition: elog.c:575
static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
Definition: spi.c:1835
int namestrcmp(Name name, const char *str)
Definition: name.c:248
static int _SPI_connected
Definition: spi.c:47
#define FirstLowInvalidHeapAttributeNumber
Definition: sysattr.h:28
static _SPI_connection * _SPI_current
Definition: spi.c:45
HeapTuple SPI_copytuple(HeapTuple tuple)
Definition: spi.c:630
void PopActiveSnapshot(void)
Definition: snapmgr.c:807
Portal SPI_cursor_open(const char *name, SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only)
Definition: spi.c:1028
uint32 SubTransactionId
Definition: c.h:398
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, Datum *values, bool *isnull)
Definition: heaptuple.c:692
QueryDesc * CreateQueryDesc(PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, int instrument_options)
Definition: pquery.c:66
ParserSetupHook parserSetup
Definition: params.h:72
bool skipData
Definition: primnodes.h:93
FormData_pg_type * Form_pg_type
Definition: pg_type.h:233
struct ParamListInfoData * ParamListInfo
Definition: params.h:62
void heap_freetuple(HeapTuple htup)
Definition: heaptuple.c:1374
unsigned int Oid
Definition: postgres_ext.h:31
HeapTuple * vals
Definition: spi.h:27
DestReceiver * None_Receiver
Definition: dest.c:91
struct ErrorContextCallback * previous
Definition: elog.h:238
Snapshot GetTransactionSnapshot(void)
Definition: snapmgr.c:300
#define DatumGetHeapTupleHeader(X)
Definition: fmgr.h:254
#define SPI_ERROR_CONNECT
Definition: spi.h:35
int natts
Definition: tupdesc.h:73
#define SPI_OK_CURSOR
Definition: spi.h:56
#define CURSOR_OPT_NO_SCROLL
Definition: parsenodes.h:2521
uint64 SPI_processed
Definition: spi.c:39
#define SearchSysCache1(cacheId, key1)
Definition: syscache.h:149
int32 tdtypmod
Definition: tupdesc.h:78
struct CachedPlan * gplan
Definition: plancache.h:104
char * SPI_gettype(TupleDesc tupdesc, int fnumber)
Definition: spi.c:851
static bool _SPI_checktuples(void)
Definition: spi.c:2460
void assign_record_type_typmod(TupleDesc tupDesc)
Definition: typcache.c:1296
#define slist_foreach_modify(iter, lhead)
Definition: ilist.h:716
TupleDesc resultDesc
Definition: plancache.h:91
char * SPI_fname(TupleDesc tupdesc, int fnumber)
Definition: spi.c:781
Portal SPI_cursor_find(const char *name)
Definition: spi.c:1331
void * copyObject(const void *from)
Definition: copyfuncs.c:4475
HeapTupleHeader t_data
Definition: htup.h:67
#define HeapTupleSetOid(tuple, oid)
Definition: htup_details.h:698
ErrorContextCallback * error_context_stack
Definition: elog.c:88
char * SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
Definition: spi.c:803
CachedPlan * SPI_plan_get_cached_plan(SPIPlanPtr plan)
Definition: spi.c:1594
void ExecutorEnd(QueryDesc *queryDesc)
Definition: execMain.c:439
int SPI_result
Definition: spi.c:42
List * pg_analyze_and_rewrite(RawStmt *parsetree, const char *query_string, Oid *paramTypes, int numParams)
Definition: postgres.c:644
static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, uint64 tcount)
Definition: spi.c:1893
void ResetUsage(void)
Definition: postgres.c:4376
void * paramFetchArg
Definition: params.h:71
#define SPI_ERROR_NOOUTFUNC
Definition: spi.h:44
SubTransactionId connectSubid
Definition: spi_priv.h:33
#define SPI_ERROR_ARGUMENT
Definition: spi.h:40
static void _SPI_error_callback(void *arg)
Definition: spi.c:2338
ParamFetchHook paramFetch
Definition: params.h:70
void pfree(void *pointer)
Definition: mcxt.c:992
static void slist_init(slist_head *head)
Definition: ilist.h:554
bool IsInParallelMode(void)
Definition: xact.c:912
#define linitial(l)
Definition: pg_list.h:110
#define ObjectIdGetDatum(X)
Definition: postgres.h:515
#define ERROR
Definition: elog.h:43
int SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params, bool read_only, long tcount)
Definition: spi.c:372
int SPI_execute_with_args(const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:440
int SPI_exec(const char *src, long tcount)
Definition: spi.c:331
CachedPlan * GetCachedPlan(CachedPlanSource *plansource, ParamListInfo boundParams, bool useResOwner)
Definition: plancache.c:1131
Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen)
Definition: spi.c:944
#define SPI_OK_INSERT_RETURNING
Definition: spi.h:57
static SPIPlanPtr _SPI_save_plan(SPIPlanPtr plan)
Definition: spi.c:2554
SPITupleTable * tuptable
Definition: spi_priv.h:26
List * pg_parse_query(const char *query_string)
Definition: postgres.c:602
ItemPointerData t_ctid
Definition: htup_details.h:150
void PushCopiedSnapshot(Snapshot snapshot)
Definition: snapmgr.c:764
ItemPointerData t_self
Definition: htup.h:65
int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls, bool read_only, long tcount)
Definition: spi.c:338
Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
Definition: spi.c:835
CachedPlanSource * CopyCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:1318
const char * SPI_result_code_string(int code)
Definition: spi.c:1509
#define ALLOCSET_DEFAULT_SIZES
Definition: memutils.h:145
static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, uint64 tcount)
Definition: spi.c:2256
Definition: dest.h:88
char * get_namespace_name(Oid nspid)
Definition: lsyscache.c:3006
Node * stmt
Definition: parsenodes.h:1337
int SPI_keepplan(SPIPlanPtr plan)
Definition: spi.c:559
static char * buf
Definition: pg_test_fsync.c:65
void PushActiveSnapshot(Snapshot snap)
Definition: snapmgr.c:728
static int _SPI_end_call(bool procmem)
Definition: spi.c:2447
bool hasReturning
Definition: plannodes.h:49
#define SPI_ERROR_NOATTRIBUTE
Definition: spi.h:43
DestReceiver * CreateDestReceiver(CommandDest dest)
Definition: dest.c:109
static MemoryContext _SPI_execmem(void)
Definition: spi.c:2415
int errdetail(const char *fmt,...)
Definition: elog.c:873
#define SPI_OK_UTILITY
Definition: spi.h:50
CachedPlanSource * CreateCachedPlan(RawStmt *raw_parse_tree, const char *query_string, const char *commandTag)
Definition: plancache.c:151
Node * utilityStmt
Definition: plannodes.h:80
#define SPI_OK_UPDATE_RETURNING
Definition: spi.h:59
void spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
Definition: spi.c:1636
int geterrposition(void)
Definition: elog.c:1257
void ReleaseCachedPlan(CachedPlan *plan, bool useResOwner)
Definition: plancache.c:1252
static _SPI_connection * _SPI_stack
Definition: spi.c:44
#define RelationGetRelationName(relation)
Definition: rel.h:433
FormData_pg_attribute * Form_pg_attribute
Definition: pg_attribute.h:184
Oid t_tableOid
Definition: htup.h:66
void(* ParserSetupHook)(struct ParseState *pstate, void *arg)
Definition: params.h:66
bool ActiveSnapshotSet(void)
Definition: snapmgr.c:846
struct Bitmapset * paramMask
Definition: params.h:75
#define RECORDOID
Definition: pg_type.h:668
MemoryContext CurrentMemoryContext
Definition: mcxt.c:37
#define SPI_OK_REWRITTEN
Definition: spi.h:60
static SPIPlanPtr _SPI_make_plan_non_temp(SPIPlanPtr plan)
Definition: spi.c:2484
PortalStrategy strategy
Definition: portal.h:142
int SPI_getargcount(SPIPlanPtr plan)
Definition: spi.c:1427
void CachedPlanSetParentContext(CachedPlanSource *plansource, MemoryContext newcontext)
Definition: plancache.c:1280
HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum, Datum *Values, const char *Nulls)
Definition: spi.c:689
#define ereport(elevel, rest)
Definition: elog.h:122
const char * CreateCommandTag(Node *parsetree)
Definition: utility.c:2012
MemoryContext savedcxt
Definition: spi_priv.h:32
Datum heap_copy_tuple_as_datum(HeapTuple tuple, TupleDesc tupleDesc)
Definition: heaptuple.c:656
void ExecutorFinish(QueryDesc *queryDesc)
Definition: execMain.c:379
MemoryContext plancxt
Definition: spi_priv.h:81
#define SPI_ERROR_TRANSACTION
Definition: spi.h:42
List * pg_analyze_and_rewrite_params(RawStmt *parsetree, const char *query_string, ParserSetupHook parserSetup, void *parserSetupArg)
Definition: postgres.c:679
int SPI_execute_snapshot(SPIPlanPtr plan, Datum *Values, const char *Nulls, Snapshot snapshot, Snapshot crosscheck_snapshot, bool read_only, bool fire_triggers, long tcount)
Definition: spi.c:406
struct ParamExternData ParamExternData
List * lappend(List *list, void *datum)
Definition: list.c:128
void * SPI_palloc(Size size)
Definition: spi.c:921
#define SPI_OK_SELINTO
Definition: spi.h:52
void ProcessUtility(PlannedStmt *pstmt, const char *queryString, ProcessUtilityContext context, ParamListInfo params, DestReceiver *dest, char *completionTag)
Definition: utility.c:332
#define WARNING
Definition: elog.h:40
HeapTuple ExecCopySlotTuple(TupleTableSlot *slot)
Definition: execTuples.c:545
#define heap_getattr(tup, attnum, tupleDesc, isnull)
Definition: htup_details.h:769
CmdType operation
Definition: execdesc.h:36
void SPI_freetuptable(SPITupleTable *tuptable)
Definition: spi.c:969
#define InvalidSnapshot
Definition: snapshot.h:25
#define MemoryContextResetAndDeleteChildren(ctx)
Definition: memutils.h:88
#define PortalIsValid(p)
Definition: portal.h:197
#define SPI_OK_FETCH
Definition: spi.h:49
uint64 pg_strtouint64(const char *str, char **endptr, int base)
Definition: numutils.c:405
#define slist_container(type, membername, ptr)
Definition: ilist.h:674
bool canSetTag
Definition: plannodes.h:53
MemoryContext AllocSetContextCreate(MemoryContext parent, const char *name, Size minContextSize, Size initBlockSize, Size maxBlockSize)
Definition: aset.c:440
void * palloc0(Size size)
Definition: mcxt.c:920
MemoryContext procCxt
Definition: spi_priv.h:30
uintptr_t Datum
Definition: postgres.h:374
Oid SPI_lastoid
Definition: spi.c:40
void CommandCounterIncrement(void)
Definition: xact.c:921
void ReleaseSysCache(HeapTuple tuple)
Definition: syscache.c:1083
bool ExecSupportsBackwardScan(Plan *node)
Definition: execAmi.c:446
MemoryContext execCxt
Definition: spi_priv.h:31
TupleDesc tupdesc
Definition: spi.h:26
bool saved
Definition: spi_priv.h:78
TupleDesc rd_att
Definition: rel.h:114
static void _SPI_cursor_operation(Portal portal, FetchDirection direction, long count, DestReceiver *dest)
Definition: spi.c:2364
#define SPI_OK_SELECT
Definition: spi.h:51
int nargs
Definition: spi_priv.h:83
Form_pg_attribute SystemAttributeDefinition(AttrNumber attno, bool relhasoids)
Definition: heap.c:198
char * SPI_getrelname(Relation rel)
Definition: spi.c:909
#define InvalidOid
Definition: postgres_ext.h:36
void SaveCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:440
int internalerrquery(const char *query)
Definition: elog.c:1161
IntoClause * into
Definition: parsenodes.h:3021
Datum datumTransfer(Datum value, bool typByVal, int typLen)
Definition: datum.c:190
#define COMPLETION_TAG_BUFSIZE
Definition: dest.h:74
#define HeapTupleIsValid(tuple)
Definition: htup.h:77
#define NULL
Definition: c.h:226
uint64 processed
Definition: spi_priv.h:24
#define Assert(condition)
Definition: c.h:671
#define lfirst(lc)
Definition: pg_list.h:106
ParserSetupHook parserSetup
Definition: spi_priv.h:85
Portal SPI_cursor_open_with_args(const char *name, const char *src, int nargs, Oid *argtypes, Datum *Values, const char *Nulls, bool read_only, int cursorOptions)
Definition: spi.c:1055
SubTransactionId GetCurrentSubTransactionId(void)
Definition: xact.c:648
void CompleteCachedPlan(CachedPlanSource *plansource, List *querytree_list, MemoryContext querytree_context, Oid *param_types, int num_params, ParserSetupHook parserSetup, void *parserSetupArg, int cursor_options, bool fixed_result)
Definition: plancache.c:324
bool oneshot
Definition: spi_priv.h:79
uint64 es_processed
Definition: execnodes.h:403
SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes, int cursorOptions)
Definition: spi.c:487
char * SPI_getnspname(Relation rel)
Definition: spi.c:915
uint16 pflags
Definition: params.h:58
const char * query_string
Definition: plancache.h:83
size_t Size
Definition: c.h:353
void AtEOXact_SPI(bool isCommit)
Definition: spi.c:186
static int list_length(const List *l)
Definition: pg_list.h:89
#define PortalGetHeapMemory(portal)
Definition: portal.h:203
void * parserSetupArg
Definition: spi_priv.h:86
#define SPI_OK_FINISH
Definition: spi.h:48
#define SPI_ERROR_TYPUNKNOWN
Definition: spi.h:45
void SPI_cursor_move(Portal portal, bool forward, long count)
Definition: spi.c:1358
void * repalloc(void *pointer, Size size)
Definition: mcxt.c:1021
struct RawStmt * raw_parse_tree
Definition: plancache.h:82
#define EXEC_FLAG_SKIP_TRIGGERS
Definition: executor.h:62
const char * name
Definition: encode.c:521
void heap_deform_tuple(HeapTuple tuple, TupleDesc tupleDesc, Datum *values, bool *isnull)
Definition: heaptuple.c:935
int SPI_freeplan(SPIPlanPtr plan)
Definition: spi.c:608
void SPI_cursor_close(Portal portal)
Definition: spi.c:1399
DestReceiver * dest
Definition: execdesc.h:41
uint64 free
Definition: spi.h:25
static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, ParamListInfo paramLI, bool read_only)
Definition: spi.c:1120
bool SPI_plan_is_valid(SPIPlanPtr plan)
Definition: spi.c:1485
void(* callback)(void *arg)
Definition: elog.h:239
char * OidOutputFunctionCall(Oid functionId, Datum val)
Definition: fmgr.c:2006
void * repalloc_huge(void *pointer, Size size)
Definition: mcxt.c:1104
void * palloc(Size size)
Definition: mcxt.c:891
int errmsg(const char *fmt,...)
Definition: elog.c:797
void PortalDrop(Portal portal, bool isTopCommit)
Definition: portalmem.c:461
#define SPI_OK_UPDATE
Definition: spi.h:55
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1152
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
int i
#define CURSOR_OPT_SCROLL
Definition: parsenodes.h:2520
int SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
Definition: spi.c:365
uint64 alloced
Definition: spi.h:24
Oid SPI_getargtypeid(SPIPlanPtr plan, int argIndex)
Definition: spi.c:1412
#define errcontext
Definition: elog.h:164
#define NameStr(name)
Definition: c.h:495
List * SPI_plan_get_plan_sources(SPIPlanPtr plan)
Definition: spi.c:1578
void * arg
void SPI_cursor_fetch(Portal portal, bool forward, long count)
Definition: spi.c:1343
void DropCachedPlan(CachedPlanSource *plansource)
Definition: plancache.c:485
bool CachedPlanIsValid(CachedPlanSource *plansource)
Definition: plancache.c:1408
char * filename
Definition: parsenodes.h:1840
#define SPI_OK_INSERT
Definition: spi.h:53
struct _SPI_plan * SPIPlanPtr
Definition: spi.h:33
static void slist_delete_current(slist_mutable_iter *iter)
Definition: ilist.h:652
List * stmt_list
Definition: plancache.h:132
void * SPI_repalloc(void *pointer, Size size)
Definition: spi.c:930
int cursor_options
Definition: spi_priv.h:82
#define elog
Definition: elog.h:219
#define HeapTupleGetOid(tuple)
Definition: htup_details.h:695
int cursorOptions
Definition: portal.h:143
PlannedStmt * plannedstmt
Definition: execdesc.h:37
static MemoryContext _SPI_procmem(void)
Definition: spi.c:2421
SubTransactionId subid
Definition: spi.h:29
static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes, Datum *Values, const char *Nulls)
Definition: spi.c:2221
Definition: pg_list.h:45
bool isnull
Definition: params.h:57
long val
Definition: informix.c:689
void SPI_pfree(void *pointer)
Definition: spi.c:937
#define offsetof(type, field)
Definition: c.h:551
int errposition(int cursorpos)
Definition: elog.c:1125
#define PARAM_FLAG_CONST
Definition: params.h:52
slist_head tuptables
Definition: spi_priv.h:29
bool spi_printtup(TupleTableSlot *slot, DestReceiver *self)
Definition: spi.c:1683
SPIPlanPtr SPI_prepare_params(const char *src, ParserSetupHook parserSetup, void *parserSetupArg, int cursorOptions)
Definition: spi.c:522
int SPI_execute(const char *src, bool read_only, long tcount)
Definition: spi.c:303
static int _SPI_begin_call(bool execmem)
Definition: spi.c:2430
MemoryContext tuptabcxt
Definition: spi.h:23
MemoryContext CacheMemoryContext
Definition: mcxt.c:46
static bool Nulls[MAXATTR]
Definition: bootstrap.c:163
int internalerrposition(int cursorpos)
Definition: elog.c:1141
#define RelationGetNamespace(relation)
Definition: rel.h:440