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