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