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