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