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