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