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 = &paramLI->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