1 /*-------------------------------------------------------------------------
4 * Server Programming Interface
6 * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.158 2006/08/27 23:47:57 tgl Exp $
13 *-------------------------------------------------------------------------
17 #include "access/printtup.h"
18 #include "catalog/heap.h"
19 #include "commands/trigger.h"
20 #include "executor/spi_priv.h"
21 #include "utils/lsyscache.h"
22 #include "utils/memutils.h"
23 #include "utils/typcache.h"
26 uint32 SPI_processed = 0;
27 Oid SPI_lastoid = InvalidOid;
28 SPITupleTable *SPI_tuptable = NULL;
31 static _SPI_connection *_SPI_stack = NULL;
32 static _SPI_connection *_SPI_current = NULL;
33 static int _SPI_stack_depth = 0; /* allocated size of _SPI_stack */
34 static int _SPI_connected = -1;
35 static int _SPI_curid = -1;
37 static void _SPI_prepare_plan(const char *src, _SPI_plan *plan);
39 static int _SPI_execute_plan(_SPI_plan *plan,
40 Datum *Values, const char *Nulls,
41 Snapshot snapshot, Snapshot crosscheck_snapshot,
42 bool read_only, long tcount);
44 static int _SPI_pquery(QueryDesc *queryDesc, long tcount);
46 static void _SPI_error_callback(void *arg);
48 static void _SPI_cursor_operation(Portal portal, bool forward, long count,
51 static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location);
53 static int _SPI_begin_call(bool execmem);
54 static int _SPI_end_call(bool procmem);
55 static MemoryContext _SPI_execmem(void);
56 static MemoryContext _SPI_procmem(void);
57 static bool _SPI_checktuples(void);
60 /* =================== interface functions =================== */
68 * When procedure called by Executor _SPI_curid expected to be equal to
71 if (_SPI_curid != _SPI_connected)
72 return SPI_ERROR_CONNECT;
74 if (_SPI_stack == NULL)
76 if (_SPI_connected != -1 || _SPI_stack_depth != 0)
77 elog(ERROR, "SPI stack corrupted");
79 _SPI_stack = (_SPI_connection *)
80 MemoryContextAlloc(TopTransactionContext,
81 newdepth * sizeof(_SPI_connection));
82 _SPI_stack_depth = newdepth;
86 if (_SPI_stack_depth <= 0 || _SPI_stack_depth <= _SPI_connected)
87 elog(ERROR, "SPI stack corrupted");
88 if (_SPI_stack_depth == _SPI_connected + 1)
90 newdepth = _SPI_stack_depth * 2;
91 _SPI_stack = (_SPI_connection *)
93 newdepth * sizeof(_SPI_connection));
94 _SPI_stack_depth = newdepth;
99 * We're entering procedure where _SPI_curid == _SPI_connected - 1
102 Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth);
104 _SPI_current = &(_SPI_stack[_SPI_connected]);
105 _SPI_current->processed = 0;
106 _SPI_current->lastoid = InvalidOid;
107 _SPI_current->tuptable = NULL;
108 _SPI_current->procCxt = NULL; /* in case we fail to create 'em */
109 _SPI_current->execCxt = NULL;
110 _SPI_current->connectSubid = GetCurrentSubTransactionId();
113 * Create memory contexts for this procedure
115 * XXX it would be better to use PortalContext as the parent context, but
116 * we may not be inside a portal (consider deferred-trigger execution).
117 * Perhaps CurTransactionContext would do? For now it doesn't matter
118 * because we clean up explicitly in AtEOSubXact_SPI().
120 _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
122 ALLOCSET_DEFAULT_MINSIZE,
123 ALLOCSET_DEFAULT_INITSIZE,
124 ALLOCSET_DEFAULT_MAXSIZE);
125 _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
127 ALLOCSET_DEFAULT_MINSIZE,
128 ALLOCSET_DEFAULT_INITSIZE,
129 ALLOCSET_DEFAULT_MAXSIZE);
130 /* ... and switch to procedure's context */
131 _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
133 return SPI_OK_CONNECT;
141 res = _SPI_begin_call(false); /* live in procedure memory */
145 /* Restore memory context as it was before procedure call */
146 MemoryContextSwitchTo(_SPI_current->savedcxt);
148 /* Release memory used in procedure call */
149 MemoryContextDelete(_SPI_current->execCxt);
150 _SPI_current->execCxt = NULL;
151 MemoryContextDelete(_SPI_current->procCxt);
152 _SPI_current->procCxt = NULL;
155 * Reset result variables, especially SPI_tuptable which is probably
156 * pointing at a just-deleted tuptable
159 SPI_lastoid = InvalidOid;
163 * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are closing
164 * connection to SPI and returning to upper Executor and so _SPI_connected
165 * must be equal to _SPI_curid.
169 if (_SPI_connected == -1)
172 _SPI_current = &(_SPI_stack[_SPI_connected]);
174 return SPI_OK_FINISH;
178 * Clean up SPI state at transaction commit or abort.
181 AtEOXact_SPI(bool isCommit)
184 * Note that memory contexts belonging to SPI stack entries will be freed
185 * automatically, so we can ignore them here. We just need to restore our
186 * static variables to initial state.
188 if (isCommit && _SPI_connected != -1)
190 (errcode(ERRCODE_WARNING),
191 errmsg("transaction left non-empty SPI stack"),
192 errhint("Check for missing \"SPI_finish\" calls.")));
194 _SPI_current = _SPI_stack = NULL;
195 _SPI_stack_depth = 0;
196 _SPI_connected = _SPI_curid = -1;
198 SPI_lastoid = InvalidOid;
203 * Clean up SPI state at subtransaction commit or abort.
205 * During commit, there shouldn't be any unclosed entries remaining from
206 * the current subtransaction; we emit a warning if any are found.
209 AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
213 while (_SPI_connected >= 0)
215 _SPI_connection *connection = &(_SPI_stack[_SPI_connected]);
217 if (connection->connectSubid != mySubid)
218 break; /* couldn't be any underneath it either */
223 * Release procedure memory explicitly (see note in SPI_connect)
225 if (connection->execCxt)
227 MemoryContextDelete(connection->execCxt);
228 connection->execCxt = NULL;
230 if (connection->procCxt)
232 MemoryContextDelete(connection->procCxt);
233 connection->procCxt = NULL;
237 * Pop the stack entry and reset global variables. Unlike
238 * SPI_finish(), we don't risk switching to memory contexts that might
242 _SPI_curid = _SPI_connected;
243 if (_SPI_connected == -1)
246 _SPI_current = &(_SPI_stack[_SPI_connected]);
248 SPI_lastoid = InvalidOid;
252 if (found && isCommit)
254 (errcode(ERRCODE_WARNING),
255 errmsg("subtransaction left non-empty SPI stack"),
256 errhint("Check for missing \"SPI_finish\" calls.")));
260 /* Pushes SPI stack to allow recursive SPI calls */
267 /* Pops SPI stack to allow recursive SPI calls */
274 /* Restore state of SPI stack after aborting a subtransaction */
276 SPI_restore_connection(void)
278 Assert(_SPI_connected >= 0);
279 _SPI_curid = _SPI_connected - 1;
282 /* Parse, plan, and execute a query string */
284 SPI_execute(const char *src, bool read_only, long tcount)
289 if (src == NULL || tcount < 0)
290 return SPI_ERROR_ARGUMENT;
292 res = _SPI_begin_call(true);
296 plan.plancxt = NULL; /* doesn't have own context */
299 plan.argtypes = NULL;
301 _SPI_prepare_plan(src, &plan);
303 res = _SPI_execute_plan(&plan, NULL, NULL,
304 InvalidSnapshot, InvalidSnapshot,
311 /* Obsolete version of SPI_execute */
313 SPI_exec(const char *src, long tcount)
315 return SPI_execute(src, false, tcount);
318 /* Execute a previously prepared plan */
320 SPI_execute_plan(void *plan, Datum *Values, const char *Nulls,
321 bool read_only, long tcount)
325 if (plan == NULL || tcount < 0)
326 return SPI_ERROR_ARGUMENT;
328 if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
329 return SPI_ERROR_PARAM;
331 res = _SPI_begin_call(true);
335 res = _SPI_execute_plan((_SPI_plan *) plan,
337 InvalidSnapshot, InvalidSnapshot,
344 /* Obsolete version of SPI_execute_plan */
346 SPI_execp(void *plan, Datum *Values, const char *Nulls, long tcount)
348 return SPI_execute_plan(plan, Values, Nulls, false, tcount);
352 * SPI_execute_snapshot -- identical to SPI_execute_plan, except that we allow
353 * the caller to specify exactly which snapshots to use. This is currently
354 * not documented in spi.sgml because it is only intended for use by RI
357 * Passing snapshot == InvalidSnapshot will select the normal behavior of
358 * fetching a new snapshot for each query.
361 SPI_execute_snapshot(void *plan,
362 Datum *Values, const char *Nulls,
363 Snapshot snapshot, Snapshot crosscheck_snapshot,
364 bool read_only, long tcount)
368 if (plan == NULL || tcount < 0)
369 return SPI_ERROR_ARGUMENT;
371 if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
372 return SPI_ERROR_PARAM;
374 res = _SPI_begin_call(true);
378 res = _SPI_execute_plan((_SPI_plan *) plan,
380 snapshot, crosscheck_snapshot,
388 SPI_prepare(const char *src, int nargs, Oid *argtypes)
393 if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
395 SPI_result = SPI_ERROR_ARGUMENT;
399 SPI_result = _SPI_begin_call(true);
403 plan.plancxt = NULL; /* doesn't have own context */
406 plan.argtypes = argtypes;
408 _SPI_prepare_plan(src, &plan);
410 /* copy plan to procedure context */
411 result = _SPI_copy_plan(&plan, _SPI_CPLAN_PROCXT);
415 return (void *) result;
419 SPI_saveplan(void *plan)
425 SPI_result = SPI_ERROR_ARGUMENT;
429 SPI_result = _SPI_begin_call(false); /* don't change context */
433 newplan = _SPI_copy_plan((_SPI_plan *) plan, _SPI_CPLAN_TOPCXT);
438 return (void *) newplan;
442 SPI_freeplan(void *plan)
444 _SPI_plan *spiplan = (_SPI_plan *) plan;
447 return SPI_ERROR_ARGUMENT;
449 MemoryContextDelete(spiplan->plancxt);
454 SPI_copytuple(HeapTuple tuple)
456 MemoryContext oldcxt = NULL;
461 SPI_result = SPI_ERROR_ARGUMENT;
465 if (_SPI_curid + 1 == _SPI_connected) /* connected */
467 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
468 elog(ERROR, "SPI stack corrupted");
469 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
472 ctuple = heap_copytuple(tuple);
475 MemoryContextSwitchTo(oldcxt);
481 SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
483 MemoryContext oldcxt = NULL;
484 HeapTupleHeader dtup;
486 if (tuple == NULL || tupdesc == NULL)
488 SPI_result = SPI_ERROR_ARGUMENT;
492 /* For RECORD results, make sure a typmod has been assigned */
493 if (tupdesc->tdtypeid == RECORDOID &&
494 tupdesc->tdtypmod < 0)
495 assign_record_type_typmod(tupdesc);
497 if (_SPI_curid + 1 == _SPI_connected) /* connected */
499 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
500 elog(ERROR, "SPI stack corrupted");
501 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
504 dtup = (HeapTupleHeader) palloc(tuple->t_len);
505 memcpy((char *) dtup, (char *) tuple->t_data, tuple->t_len);
507 HeapTupleHeaderSetDatumLength(dtup, tuple->t_len);
508 HeapTupleHeaderSetTypeId(dtup, tupdesc->tdtypeid);
509 HeapTupleHeaderSetTypMod(dtup, tupdesc->tdtypmod);
512 MemoryContextSwitchTo(oldcxt);
518 SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
519 Datum *Values, const char *Nulls)
521 MemoryContext oldcxt = NULL;
523 int numberOfAttributes;
528 if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
530 SPI_result = SPI_ERROR_ARGUMENT;
534 if (_SPI_curid + 1 == _SPI_connected) /* connected */
536 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
537 elog(ERROR, "SPI stack corrupted");
538 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
541 numberOfAttributes = rel->rd_att->natts;
542 v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
543 n = (char *) palloc(numberOfAttributes * sizeof(char));
545 /* fetch old values and nulls */
546 heap_deformtuple(tuple, rel->rd_att, v, n);
548 /* replace values and nulls */
549 for (i = 0; i < natts; i++)
551 if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
553 v[attnum[i] - 1] = Values[i];
554 n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? 'n' : ' ';
557 if (i == natts) /* no errors in *attnum */
559 mtuple = heap_formtuple(rel->rd_att, v, n);
562 * copy the identification info of the old tuple: t_ctid, t_self, and
565 mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
566 mtuple->t_self = tuple->t_self;
567 mtuple->t_tableOid = tuple->t_tableOid;
568 if (rel->rd_att->tdhasoid)
569 HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
574 SPI_result = SPI_ERROR_NOATTRIBUTE;
581 MemoryContextSwitchTo(oldcxt);
587 SPI_fnumber(TupleDesc tupdesc, const char *fname)
590 Form_pg_attribute sysatt;
592 for (res = 0; res < tupdesc->natts; res++)
594 if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0)
598 sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ );
600 return sysatt->attnum;
602 /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
603 return SPI_ERROR_NOATTRIBUTE;
607 SPI_fname(TupleDesc tupdesc, int fnumber)
609 Form_pg_attribute att;
613 if (fnumber > tupdesc->natts || fnumber == 0 ||
614 fnumber <= FirstLowInvalidHeapAttributeNumber)
616 SPI_result = SPI_ERROR_NOATTRIBUTE;
621 att = tupdesc->attrs[fnumber - 1];
623 att = SystemAttributeDefinition(fnumber, true);
625 return pstrdup(NameStr(att->attname));
629 SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
641 if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||
642 fnumber <= FirstLowInvalidHeapAttributeNumber)
644 SPI_result = SPI_ERROR_NOATTRIBUTE;
648 origval = heap_getattr(tuple, fnumber, tupdesc, &isnull);
653 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
655 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
657 getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
660 * If we have a toasted datum, forcibly detoast it here to avoid memory
661 * leakage inside the type's output routine.
664 val = PointerGetDatum(PG_DETOAST_DATUM(origval));
668 result = OidOutputFunctionCall(foutoid, val);
670 /* Clean up detoasted copy, if any */
672 pfree(DatumGetPointer(val));
678 SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
682 if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||
683 fnumber <= FirstLowInvalidHeapAttributeNumber)
685 SPI_result = SPI_ERROR_NOATTRIBUTE;
690 return heap_getattr(tuple, fnumber, tupdesc, isnull);
694 SPI_gettype(TupleDesc tupdesc, int fnumber)
702 if (fnumber > tupdesc->natts || fnumber == 0 ||
703 fnumber <= FirstLowInvalidHeapAttributeNumber)
705 SPI_result = SPI_ERROR_NOATTRIBUTE;
710 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
712 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
714 typeTuple = SearchSysCache(TYPEOID,
715 ObjectIdGetDatum(typoid),
718 if (!HeapTupleIsValid(typeTuple))
720 SPI_result = SPI_ERROR_TYPUNKNOWN;
724 result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
725 ReleaseSysCache(typeTuple);
730 SPI_gettypeid(TupleDesc tupdesc, int fnumber)
734 if (fnumber > tupdesc->natts || fnumber == 0 ||
735 fnumber <= FirstLowInvalidHeapAttributeNumber)
737 SPI_result = SPI_ERROR_NOATTRIBUTE;
742 return tupdesc->attrs[fnumber - 1]->atttypid;
744 return (SystemAttributeDefinition(fnumber, true))->atttypid;
748 SPI_getrelname(Relation rel)
750 return pstrdup(RelationGetRelationName(rel));
754 SPI_getnspname(Relation rel)
756 return get_namespace_name(RelationGetNamespace(rel));
760 SPI_palloc(Size size)
762 MemoryContext oldcxt = NULL;
765 if (_SPI_curid + 1 == _SPI_connected) /* connected */
767 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
768 elog(ERROR, "SPI stack corrupted");
769 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
772 pointer = palloc(size);
775 MemoryContextSwitchTo(oldcxt);
781 SPI_repalloc(void *pointer, Size size)
783 /* No longer need to worry which context chunk was in... */
784 return repalloc(pointer, size);
788 SPI_pfree(void *pointer)
790 /* No longer need to worry which context chunk was in... */
795 SPI_freetuple(HeapTuple tuple)
797 /* No longer need to worry which context tuple was in... */
798 heap_freetuple(tuple);
802 SPI_freetuptable(SPITupleTable *tuptable)
804 if (tuptable != NULL)
805 MemoryContextDelete(tuptable->tuptabcxt);
813 * Open a prepared SPI plan as a portal
816 SPI_cursor_open(const char *name, void *plan,
817 Datum *Values, const char *Nulls,
820 _SPI_plan *spiplan = (_SPI_plan *) plan;
823 ParamListInfo paramLI;
825 MemoryContext oldcontext;
830 * Check that the plan is something the Portal code will special-case
831 * as returning one tupleset.
833 if (!SPI_is_cursor_plan(spiplan))
835 /* try to give a good error message */
838 if (list_length(spiplan->qtlist) != 1)
840 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
841 errmsg("cannot open multi-query plan as cursor")));
842 queryTree = PortalListGetPrimaryQuery((List *) linitial(spiplan->qtlist));
843 if (queryTree == NULL)
845 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
846 errmsg("cannot open empty query as cursor")));
848 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
849 /* translator: %s is name of a SQL command, eg INSERT */
850 errmsg("cannot open %s query as cursor",
851 CreateQueryTag(queryTree))));
854 Assert(list_length(spiplan->qtlist) == 1);
855 qtlist = (List *) linitial(spiplan->qtlist);
856 ptlist = spiplan->ptlist;
857 if (list_length(qtlist) != list_length(ptlist))
858 elog(ERROR, "corrupted SPI plan lists");
860 /* Reset SPI result (note we deliberately don't touch lastoid) */
863 _SPI_current->processed = 0;
864 _SPI_current->tuptable = NULL;
866 /* Create the portal */
867 if (name == NULL || name[0] == '\0')
869 /* Use a random nonconflicting name */
870 portal = CreateNewPortal();
874 /* In this path, error if portal of same name already exists */
875 portal = CreatePortal(name, false, false);
878 /* Switch to portal's memory and copy the parsetrees and plans to there */
879 oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
880 qtlist = copyObject(qtlist);
881 ptlist = copyObject(ptlist);
883 /* If the plan has parameters, set them up */
884 if (spiplan->nargs > 0)
886 /* sizeof(ParamListInfoData) includes the first array element */
887 paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
888 (spiplan->nargs - 1) * sizeof(ParamExternData));
889 paramLI->numParams = spiplan->nargs;
891 for (k = 0; k < spiplan->nargs; k++)
893 ParamExternData *prm = ¶mLI->params[k];
895 prm->ptype = spiplan->argtypes[k];
896 prm->isnull = (Nulls && Nulls[k] == 'n');
899 /* nulls just copy */
900 prm->value = Values[k];
904 /* pass-by-ref values must be copied into portal context */
908 get_typlenbyval(prm->ptype, ¶mTypLen, ¶mTypByVal);
909 prm->value = datumCopy(Values[k],
910 paramTypByVal, paramTypLen);
920 PortalDefineQuery(portal,
921 NULL, /* no statement name */
923 CreateQueryTag(PortalListGetPrimaryQuery(qtlist)),
926 PortalGetHeapMemory(portal));
928 MemoryContextSwitchTo(oldcontext);
931 * Set up options for portal.
933 portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL);
934 if (list_length(ptlist) == 1 &&
935 ExecSupportsBackwardScan((Plan *) linitial(ptlist)))
936 portal->cursorOptions |= CURSOR_OPT_SCROLL;
938 portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
941 * Set up the snapshot to use. (PortalStart will do CopySnapshot, so we
945 snapshot = ActiveSnapshot;
948 CommandCounterIncrement();
949 snapshot = GetTransactionSnapshot();
953 * Start portal execution.
955 PortalStart(portal, paramLI, snapshot);
957 Assert(portal->strategy != PORTAL_MULTI_QUERY);
959 /* Return the created portal */
967 * Find the portal of an existing open cursor
970 SPI_cursor_find(const char *name)
972 return GetPortalByName(name);
979 * Fetch rows in a cursor
982 SPI_cursor_fetch(Portal portal, bool forward, long count)
984 _SPI_cursor_operation(portal, forward, count,
985 CreateDestReceiver(DestSPI, NULL));
986 /* we know that the DestSPI receiver doesn't need a destroy call */
996 SPI_cursor_move(Portal portal, bool forward, long count)
998 _SPI_cursor_operation(portal, forward, count, None_Receiver);
1003 * SPI_cursor_close()
1008 SPI_cursor_close(Portal portal)
1010 if (!PortalIsValid(portal))
1011 elog(ERROR, "invalid portal in SPI cursor operation");
1013 PortalDrop(portal, false);
1017 * Returns the Oid representing the type id for argument at argIndex. First
1018 * parameter is at index zero.
1021 SPI_getargtypeid(void *plan, int argIndex)
1023 if (plan == NULL || argIndex < 0 || argIndex >= ((_SPI_plan *) plan)->nargs)
1025 SPI_result = SPI_ERROR_ARGUMENT;
1028 return ((_SPI_plan *) plan)->argtypes[argIndex];
1032 * Returns the number of arguments for the prepared plan.
1035 SPI_getargcount(void *plan)
1039 SPI_result = SPI_ERROR_ARGUMENT;
1042 return ((_SPI_plan *) plan)->nargs;
1046 * Returns true if the plan contains exactly one command
1047 * and that command returns tuples to the caller (eg, SELECT or
1048 * INSERT ... RETURNING, but not SELECT ... INTO). In essence,
1049 * the result indicates if the command can be used with SPI_cursor_open
1052 * plan: A plan previously prepared using SPI_prepare
1055 SPI_is_cursor_plan(void *plan)
1057 _SPI_plan *spiplan = (_SPI_plan *) plan;
1059 if (spiplan == NULL)
1061 SPI_result = SPI_ERROR_ARGUMENT;
1065 if (list_length(spiplan->qtlist) != 1)
1066 return false; /* not exactly 1 pre-rewrite command */
1068 switch (ChoosePortalStrategy((List *) linitial(spiplan->qtlist)))
1070 case PORTAL_ONE_SELECT:
1071 case PORTAL_ONE_RETURNING:
1072 case PORTAL_UTIL_SELECT:
1076 case PORTAL_MULTI_QUERY:
1077 /* will not return tuples */
1084 * SPI_result_code_string --- convert any SPI return code to a string
1086 * This is often useful in error messages. Most callers will probably
1087 * only pass negative (error-case) codes, but for generality we recognize
1088 * the success codes too.
1091 SPI_result_code_string(int code)
1093 static char buf[64];
1097 case SPI_ERROR_CONNECT:
1098 return "SPI_ERROR_CONNECT";
1099 case SPI_ERROR_COPY:
1100 return "SPI_ERROR_COPY";
1101 case SPI_ERROR_OPUNKNOWN:
1102 return "SPI_ERROR_OPUNKNOWN";
1103 case SPI_ERROR_UNCONNECTED:
1104 return "SPI_ERROR_UNCONNECTED";
1105 case SPI_ERROR_CURSOR:
1106 return "SPI_ERROR_CURSOR";
1107 case SPI_ERROR_ARGUMENT:
1108 return "SPI_ERROR_ARGUMENT";
1109 case SPI_ERROR_PARAM:
1110 return "SPI_ERROR_PARAM";
1111 case SPI_ERROR_TRANSACTION:
1112 return "SPI_ERROR_TRANSACTION";
1113 case SPI_ERROR_NOATTRIBUTE:
1114 return "SPI_ERROR_NOATTRIBUTE";
1115 case SPI_ERROR_NOOUTFUNC:
1116 return "SPI_ERROR_NOOUTFUNC";
1117 case SPI_ERROR_TYPUNKNOWN:
1118 return "SPI_ERROR_TYPUNKNOWN";
1119 case SPI_OK_CONNECT:
1120 return "SPI_OK_CONNECT";
1122 return "SPI_OK_FINISH";
1124 return "SPI_OK_FETCH";
1125 case SPI_OK_UTILITY:
1126 return "SPI_OK_UTILITY";
1128 return "SPI_OK_SELECT";
1129 case SPI_OK_SELINTO:
1130 return "SPI_OK_SELINTO";
1132 return "SPI_OK_INSERT";
1134 return "SPI_OK_DELETE";
1136 return "SPI_OK_UPDATE";
1138 return "SPI_OK_CURSOR";
1139 case SPI_OK_INSERT_RETURNING:
1140 return "SPI_OK_INSERT_RETURNING";
1141 case SPI_OK_DELETE_RETURNING:
1142 return "SPI_OK_DELETE_RETURNING";
1143 case SPI_OK_UPDATE_RETURNING:
1144 return "SPI_OK_UPDATE_RETURNING";
1146 /* Unrecognized code ... return something useful ... */
1147 sprintf(buf, "Unrecognized SPI code %d", code);
1151 /* =================== private functions =================== */
1155 * Initialize to receive tuples from Executor into SPITupleTable
1156 * of current SPI procedure
1159 spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
1161 SPITupleTable *tuptable;
1162 MemoryContext oldcxt;
1163 MemoryContext tuptabcxt;
1166 * When called by Executor _SPI_curid expected to be equal to
1169 if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1170 elog(ERROR, "improper call to spi_dest_startup");
1171 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1172 elog(ERROR, "SPI stack corrupted");
1174 if (_SPI_current->tuptable != NULL)
1175 elog(ERROR, "improper call to spi_dest_startup");
1177 oldcxt = _SPI_procmem(); /* switch to procedure memory context */
1179 tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,
1181 ALLOCSET_DEFAULT_MINSIZE,
1182 ALLOCSET_DEFAULT_INITSIZE,
1183 ALLOCSET_DEFAULT_MAXSIZE);
1184 MemoryContextSwitchTo(tuptabcxt);
1186 _SPI_current->tuptable = tuptable = (SPITupleTable *)
1187 palloc(sizeof(SPITupleTable));
1188 tuptable->tuptabcxt = tuptabcxt;
1189 tuptable->alloced = tuptable->free = 128;
1190 tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
1191 tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
1193 MemoryContextSwitchTo(oldcxt);
1198 * store tuple retrieved by Executor into SPITupleTable
1199 * of current SPI procedure
1202 spi_printtup(TupleTableSlot *slot, DestReceiver *self)
1204 SPITupleTable *tuptable;
1205 MemoryContext oldcxt;
1208 * When called by Executor _SPI_curid expected to be equal to
1211 if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1212 elog(ERROR, "improper call to spi_printtup");
1213 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1214 elog(ERROR, "SPI stack corrupted");
1216 tuptable = _SPI_current->tuptable;
1217 if (tuptable == NULL)
1218 elog(ERROR, "improper call to spi_printtup");
1220 oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
1222 if (tuptable->free == 0)
1224 tuptable->free = 256;
1225 tuptable->alloced += tuptable->free;
1226 tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
1227 tuptable->alloced * sizeof(HeapTuple));
1230 tuptable->vals[tuptable->alloced - tuptable->free] =
1231 ExecCopySlotTuple(slot);
1234 MemoryContextSwitchTo(oldcxt);
1242 * Parse and plan a querystring.
1244 * At entry, plan->argtypes and plan->nargs must be valid.
1246 * Query and plan lists are stored into *plan.
1249 _SPI_prepare_plan(const char *src, _SPI_plan *plan)
1251 List *raw_parsetree_list;
1252 List *query_list_list;
1254 ListCell *list_item;
1255 ErrorContextCallback spierrcontext;
1256 Oid *argtypes = plan->argtypes;
1257 int nargs = plan->nargs;
1260 * Increment CommandCounter to see changes made by now. We must do this
1261 * to be sure of seeing any schema changes made by a just-preceding SPI
1262 * command. (But we don't bother advancing the snapshot, since the
1263 * planner generally operates under SnapshotNow rules anyway.)
1265 CommandCounterIncrement();
1268 * Setup error traceback support for ereport()
1270 spierrcontext.callback = _SPI_error_callback;
1271 spierrcontext.arg = (void *) src;
1272 spierrcontext.previous = error_context_stack;
1273 error_context_stack = &spierrcontext;
1276 * Parse the request string into a list of raw parse trees.
1278 raw_parsetree_list = pg_parse_query(src);
1281 * Do parse analysis and rule rewrite for each raw parsetree.
1283 * We save the querytrees from each raw parsetree as a separate sublist.
1284 * This allows _SPI_execute_plan() to know where the boundaries between
1285 * original queries fall.
1287 query_list_list = NIL;
1290 foreach(list_item, raw_parsetree_list)
1292 Node *parsetree = (Node *) lfirst(list_item);
1295 query_list = pg_analyze_and_rewrite(parsetree, src, argtypes, nargs);
1297 query_list_list = lappend(query_list_list, query_list);
1299 plan_list = list_concat(plan_list,
1300 pg_plan_queries(query_list, NULL, false));
1303 plan->qtlist = query_list_list;
1304 plan->ptlist = plan_list;
1307 * Pop the error context stack
1309 error_context_stack = spierrcontext.previous;
1313 * Execute the given plan with the given parameter values
1315 * snapshot: query snapshot to use, or InvalidSnapshot for the normal
1316 * behavior of taking a new snapshot for each query.
1317 * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
1318 * read_only: TRUE for read-only execution (no CommandCounterIncrement)
1319 * tcount: execution tuple-count limit, or 0 for none
1322 _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
1323 Snapshot snapshot, Snapshot crosscheck_snapshot,
1324 bool read_only, long tcount)
1326 volatile int my_res = 0;
1327 volatile uint32 my_processed = 0;
1328 volatile Oid my_lastoid = InvalidOid;
1329 SPITupleTable *volatile my_tuptable = NULL;
1330 Snapshot saveActiveSnapshot;
1332 /* Be sure to restore ActiveSnapshot on error exit */
1333 saveActiveSnapshot = ActiveSnapshot;
1336 List *query_list_list = plan->qtlist;
1337 ListCell *plan_list_item = list_head(plan->ptlist);
1338 ListCell *query_list_list_item;
1339 ErrorContextCallback spierrcontext;
1340 int nargs = plan->nargs;
1341 ParamListInfo paramLI;
1343 /* Convert parameters to form wanted by executor */
1348 /* sizeof(ParamListInfoData) includes the first array element */
1349 paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
1350 (nargs - 1) * sizeof(ParamExternData));
1351 paramLI->numParams = nargs;
1353 for (k = 0; k < nargs; k++)
1355 ParamExternData *prm = ¶mLI->params[k];
1357 prm->value = Values[k];
1358 prm->isnull = (Nulls && Nulls[k] == 'n');
1359 prm->ptype = plan->argtypes[k];
1366 * Setup error traceback support for ereport()
1368 spierrcontext.callback = _SPI_error_callback;
1369 spierrcontext.arg = (void *) plan->query;
1370 spierrcontext.previous = error_context_stack;
1371 error_context_stack = &spierrcontext;
1373 foreach(query_list_list_item, query_list_list)
1375 List *query_list = lfirst(query_list_list_item);
1376 ListCell *query_list_item;
1378 foreach(query_list_item, query_list)
1380 Query *queryTree = (Query *) lfirst(query_list_item);
1386 planTree = lfirst(plan_list_item);
1387 plan_list_item = lnext(plan_list_item);
1389 _SPI_current->processed = 0;
1390 _SPI_current->lastoid = InvalidOid;
1391 _SPI_current->tuptable = NULL;
1393 if (queryTree->commandType == CMD_UTILITY)
1395 if (IsA(queryTree->utilityStmt, CopyStmt))
1397 CopyStmt *stmt = (CopyStmt *) queryTree->utilityStmt;
1399 if (stmt->filename == NULL)
1401 my_res = SPI_ERROR_COPY;
1405 else if (IsA(queryTree->utilityStmt, DeclareCursorStmt) ||
1406 IsA(queryTree->utilityStmt, ClosePortalStmt) ||
1407 IsA(queryTree->utilityStmt, FetchStmt))
1409 my_res = SPI_ERROR_CURSOR;
1412 else if (IsA(queryTree->utilityStmt, TransactionStmt))
1414 my_res = SPI_ERROR_TRANSACTION;
1419 if (read_only && !QueryIsReadOnly(queryTree))
1421 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1422 /* translator: %s is a SQL statement name */
1423 errmsg("%s is not allowed in a non-volatile function",
1424 CreateQueryTag(queryTree))));
1427 * If not read-only mode, advance the command counter before
1431 CommandCounterIncrement();
1433 dest = CreateDestReceiver(queryTree->canSetTag ? DestSPI : DestNone,
1436 if (snapshot == InvalidSnapshot)
1439 * Default read_only behavior is to use the entry-time
1440 * ActiveSnapshot; if read-write, grab a full new snap.
1443 ActiveSnapshot = CopySnapshot(saveActiveSnapshot);
1445 ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
1450 * We interpret read_only with a specified snapshot to be
1451 * exactly that snapshot, but read-write means use the
1452 * snap with advancing of command ID.
1454 ActiveSnapshot = CopySnapshot(snapshot);
1456 ActiveSnapshot->curcid = GetCurrentCommandId();
1459 if (queryTree->commandType == CMD_UTILITY)
1461 ProcessUtility(queryTree->utilityStmt, paramLI,
1463 /* Update "processed" if stmt returned tuples */
1464 if (_SPI_current->tuptable)
1465 _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free;
1466 res = SPI_OK_UTILITY;
1470 qdesc = CreateQueryDesc(queryTree, planTree,
1472 crosscheck_snapshot,
1475 res = _SPI_pquery(qdesc,
1476 queryTree->canSetTag ? tcount : 0);
1477 FreeQueryDesc(qdesc);
1479 FreeSnapshot(ActiveSnapshot);
1480 ActiveSnapshot = NULL;
1483 * The last canSetTag query sets the status values returned
1484 * to the caller. Be careful to free any tuptables not
1485 * returned, to avoid intratransaction memory leak.
1487 if (queryTree->canSetTag)
1489 my_processed = _SPI_current->processed;
1490 my_lastoid = _SPI_current->lastoid;
1491 SPI_freetuptable(my_tuptable);
1492 my_tuptable = _SPI_current->tuptable;
1497 SPI_freetuptable(_SPI_current->tuptable);
1498 _SPI_current->tuptable = NULL;
1500 /* we know that the receiver doesn't need a destroy call */
1512 * Pop the error context stack
1514 error_context_stack = spierrcontext.previous;
1518 /* Restore global vars and propagate error */
1519 ActiveSnapshot = saveActiveSnapshot;
1524 ActiveSnapshot = saveActiveSnapshot;
1526 /* Save results for caller */
1527 SPI_processed = my_processed;
1528 SPI_lastoid = my_lastoid;
1529 SPI_tuptable = my_tuptable;
1535 _SPI_pquery(QueryDesc *queryDesc, long tcount)
1537 int operation = queryDesc->operation;
1543 if (queryDesc->parsetree->into) /* select into table? */
1544 res = SPI_OK_SELINTO;
1545 else if (queryDesc->dest->mydest != DestSPI)
1547 /* Don't return SPI_OK_SELECT if we're discarding result */
1548 res = SPI_OK_UTILITY;
1551 res = SPI_OK_SELECT;
1554 if (queryDesc->parsetree->returningList)
1555 res = SPI_OK_INSERT_RETURNING;
1557 res = SPI_OK_INSERT;
1560 if (queryDesc->parsetree->returningList)
1561 res = SPI_OK_DELETE_RETURNING;
1563 res = SPI_OK_DELETE;
1566 if (queryDesc->parsetree->returningList)
1567 res = SPI_OK_UPDATE_RETURNING;
1569 res = SPI_OK_UPDATE;
1572 return SPI_ERROR_OPUNKNOWN;
1575 #ifdef SPI_EXECUTOR_STATS
1576 if (ShowExecutorStats)
1580 AfterTriggerBeginQuery();
1582 ExecutorStart(queryDesc, 0);
1584 ExecutorRun(queryDesc, ForwardScanDirection, tcount);
1586 _SPI_current->processed = queryDesc->estate->es_processed;
1587 _SPI_current->lastoid = queryDesc->estate->es_lastoid;
1589 if ((res == SPI_OK_SELECT || queryDesc->parsetree->returningList) &&
1590 queryDesc->dest->mydest == DestSPI)
1592 if (_SPI_checktuples())
1593 elog(ERROR, "consistency check on SPI tuple count failed");
1596 /* Take care of any queued AFTER triggers */
1597 AfterTriggerEndQuery(queryDesc->estate);
1599 ExecutorEnd(queryDesc);
1601 #ifdef SPI_EXECUTOR_STATS
1602 if (ShowExecutorStats)
1603 ShowUsage("SPI EXECUTOR STATS");
1610 * _SPI_error_callback
1612 * Add context information when a query invoked via SPI fails
1615 _SPI_error_callback(void *arg)
1617 const char *query = (const char *) arg;
1618 int syntaxerrposition;
1621 * If there is a syntax error position, convert to internal syntax error;
1622 * otherwise treat the query as an item of context stack
1624 syntaxerrposition = geterrposition();
1625 if (syntaxerrposition > 0)
1628 internalerrposition(syntaxerrposition);
1629 internalerrquery(query);
1632 errcontext("SQL statement \"%s\"", query);
1636 * _SPI_cursor_operation()
1638 * Do a FETCH or MOVE in a cursor
1641 _SPI_cursor_operation(Portal portal, bool forward, long count,
1646 /* Check that the portal is valid */
1647 if (!PortalIsValid(portal))
1648 elog(ERROR, "invalid portal in SPI cursor operation");
1650 /* Push the SPI stack */
1651 if (_SPI_begin_call(true) < 0)
1652 elog(ERROR, "SPI cursor operation called while not connected");
1654 /* Reset the SPI result (note we deliberately don't touch lastoid) */
1656 SPI_tuptable = NULL;
1657 _SPI_current->processed = 0;
1658 _SPI_current->tuptable = NULL;
1660 /* Run the cursor */
1661 nfetched = PortalRunFetch(portal,
1662 forward ? FETCH_FORWARD : FETCH_BACKWARD,
1667 * Think not to combine this store with the preceding function call. If
1668 * the portal contains calls to functions that use SPI, then SPI_stack is
1669 * likely to move around while the portal runs. When control returns,
1670 * _SPI_current will point to the correct stack entry... but the pointer
1671 * may be different than it was beforehand. So we must be sure to re-fetch
1672 * the pointer after the function call completes.
1674 _SPI_current->processed = nfetched;
1676 if (dest->mydest == DestSPI && _SPI_checktuples())
1677 elog(ERROR, "consistency check on SPI tuple count failed");
1679 /* Put the result into place for access by caller */
1680 SPI_processed = _SPI_current->processed;
1681 SPI_tuptable = _SPI_current->tuptable;
1683 /* Pop the SPI stack */
1684 _SPI_end_call(true);
1688 static MemoryContext
1691 return MemoryContextSwitchTo(_SPI_current->execCxt);
1694 static MemoryContext
1697 return MemoryContextSwitchTo(_SPI_current->procCxt);
1701 * _SPI_begin_call: begin a SPI operation within a connected procedure
1704 _SPI_begin_call(bool execmem)
1706 if (_SPI_curid + 1 != _SPI_connected)
1707 return SPI_ERROR_UNCONNECTED;
1709 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1710 elog(ERROR, "SPI stack corrupted");
1712 if (execmem) /* switch to the Executor memory context */
1719 * _SPI_end_call: end a SPI operation within a connected procedure
1721 * Note: this currently has no failure return cases, so callers don't check
1724 _SPI_end_call(bool procmem)
1727 * We're returning to procedure where _SPI_curid == _SPI_connected - 1
1731 if (procmem) /* switch to the procedure memory context */
1734 /* and free Executor memory */
1735 MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
1742 _SPI_checktuples(void)
1744 uint32 processed = _SPI_current->processed;
1745 SPITupleTable *tuptable = _SPI_current->tuptable;
1746 bool failed = false;
1748 if (tuptable == NULL) /* spi_dest_startup was not called */
1750 else if (processed != (tuptable->alloced - tuptable->free))
1757 _SPI_copy_plan(_SPI_plan *plan, int location)
1760 MemoryContext oldcxt;
1761 MemoryContext plancxt;
1762 MemoryContext parentcxt;
1764 /* Determine correct parent for the plan's memory context */
1765 if (location == _SPI_CPLAN_PROCXT)
1766 parentcxt = _SPI_current->procCxt;
1767 else if (location == _SPI_CPLAN_TOPCXT)
1768 parentcxt = TopMemoryContext;
1770 /* (this case not currently used) */
1771 parentcxt = CurrentMemoryContext;
1774 * Create a memory context for the plan. We don't expect the plan to be
1775 * very large, so use smaller-than-default alloc parameters.
1777 plancxt = AllocSetContextCreate(parentcxt,
1779 ALLOCSET_SMALL_MINSIZE,
1780 ALLOCSET_SMALL_INITSIZE,
1781 ALLOCSET_SMALL_MAXSIZE);
1782 oldcxt = MemoryContextSwitchTo(plancxt);
1784 /* Copy the SPI plan into its own context */
1785 newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
1786 newplan->plancxt = plancxt;
1787 newplan->query = pstrdup(plan->query);
1788 newplan->qtlist = (List *) copyObject(plan->qtlist);
1789 newplan->ptlist = (List *) copyObject(plan->ptlist);
1790 newplan->nargs = plan->nargs;
1791 if (plan->nargs > 0)
1793 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
1794 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
1797 newplan->argtypes = NULL;
1799 MemoryContextSwitchTo(oldcxt);