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