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