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