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