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