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