1 /*-------------------------------------------------------------------------
4 * Server Programming Interface
6 * Portions Copyright (c) 1996-2005, 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.139 2005/05/02 00:37:06 neilc 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 "tcop/tcopprot.h"
22 #include "utils/lsyscache.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
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->tuptable = NULL;
107 _SPI_current->procCxt = NULL; /* in case we fail to create 'em */
108 _SPI_current->execCxt = NULL;
109 _SPI_current->connectSubid = GetCurrentSubTransactionId();
112 * Create memory contexts for this procedure
114 * XXX it would be better to use PortalContext as the parent context, but
115 * we may not be inside a portal (consider deferred-trigger
116 * execution). Perhaps CurTransactionContext would do? For now it
117 * doesn't matter because we clean up explicitly in AtEOSubXact_SPI().
119 _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
121 ALLOCSET_DEFAULT_MINSIZE,
122 ALLOCSET_DEFAULT_INITSIZE,
123 ALLOCSET_DEFAULT_MAXSIZE);
124 _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
126 ALLOCSET_DEFAULT_MINSIZE,
127 ALLOCSET_DEFAULT_INITSIZE,
128 ALLOCSET_DEFAULT_MAXSIZE);
129 /* ... and switch to procedure's context */
130 _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
132 return SPI_OK_CONNECT;
140 res = _SPI_begin_call(false); /* live in procedure memory */
144 /* Restore memory context as it was before procedure call */
145 MemoryContextSwitchTo(_SPI_current->savedcxt);
147 /* Release memory used in procedure call */
148 MemoryContextDelete(_SPI_current->execCxt);
149 _SPI_current->execCxt = NULL;
150 MemoryContextDelete(_SPI_current->procCxt);
151 _SPI_current->procCxt = NULL;
154 * Reset result variables, especially SPI_tuptable which is probably
155 * pointing at a just-deleted tuptable
158 SPI_lastoid = InvalidOid;
162 * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are
163 * closing connection to SPI and returning to upper Executor and so
164 * _SPI_connected must be equal to _SPI_curid.
168 if (_SPI_connected == -1)
171 _SPI_current = &(_SPI_stack[_SPI_connected]);
173 return SPI_OK_FINISH;
177 * Clean up SPI state at transaction commit or abort.
180 AtEOXact_SPI(bool isCommit)
183 * Note that memory contexts belonging to SPI stack entries will be
184 * freed automatically, so we can ignore them here. We just need to
185 * restore our static variables to initial state.
187 if (isCommit && _SPI_connected != -1)
189 (errcode(ERRCODE_WARNING),
190 errmsg("transaction left non-empty SPI stack"),
191 errhint("Check for missing \"SPI_finish\" calls.")));
193 _SPI_current = _SPI_stack = NULL;
194 _SPI_stack_depth = 0;
195 _SPI_connected = _SPI_curid = -1;
197 SPI_lastoid = InvalidOid;
202 * Clean up SPI state at subtransaction commit or abort.
204 * During commit, there shouldn't be any unclosed entries remaining from
205 * the current subtransaction; we emit a warning if any are found.
208 AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
212 while (_SPI_connected >= 0)
214 _SPI_connection *connection = &(_SPI_stack[_SPI_connected]);
216 if (connection->connectSubid != mySubid)
217 break; /* couldn't be any underneath it either */
222 * Release procedure memory explicitly (see note in SPI_connect)
224 if (connection->execCxt)
226 MemoryContextDelete(connection->execCxt);
227 connection->execCxt = NULL;
229 if (connection->procCxt)
231 MemoryContextDelete(connection->procCxt);
232 connection->procCxt = NULL;
236 * Pop the stack entry and reset global variables. Unlike
237 * SPI_finish(), we don't risk switching to memory contexts that
238 * might be already gone.
241 _SPI_curid = _SPI_connected;
242 if (_SPI_connected == -1)
245 _SPI_current = &(_SPI_stack[_SPI_connected]);
247 SPI_lastoid = InvalidOid;
251 if (found && isCommit)
253 (errcode(ERRCODE_WARNING),
254 errmsg("subtransaction left non-empty SPI stack"),
255 errhint("Check for missing \"SPI_finish\" calls.")));
259 /* Pushes SPI stack to allow recursive SPI calls */
266 /* Pops SPI stack to allow recursive SPI calls */
273 /* Restore state of SPI stack after aborting a subtransaction */
275 SPI_restore_connection(void)
277 Assert(_SPI_connected >= 0);
278 _SPI_curid = _SPI_connected - 1;
281 /* Parse, plan, and execute a query string */
283 SPI_execute(const char *src, bool read_only, long tcount)
288 if (src == NULL || tcount < 0)
289 return SPI_ERROR_ARGUMENT;
291 res = _SPI_begin_call(true);
295 plan.plancxt = NULL; /* doesn't have own context */
298 plan.argtypes = NULL;
300 _SPI_prepare_plan(src, &plan);
302 res = _SPI_execute_plan(&plan, NULL, NULL,
303 InvalidSnapshot, InvalidSnapshot,
310 /* Obsolete version of SPI_execute */
312 SPI_exec(const char *src, long tcount)
314 return SPI_execute(src, false, tcount);
317 /* Execute a previously prepared plan */
319 SPI_execute_plan(void *plan, Datum *Values, const char *Nulls,
320 bool read_only, long tcount)
324 if (plan == NULL || tcount < 0)
325 return SPI_ERROR_ARGUMENT;
327 if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
328 return SPI_ERROR_PARAM;
330 res = _SPI_begin_call(true);
334 res = _SPI_execute_plan((_SPI_plan *) plan,
336 InvalidSnapshot, InvalidSnapshot,
343 /* Obsolete version of SPI_execute_plan */
345 SPI_execp(void *plan, Datum *Values, const char *Nulls, long tcount)
347 return SPI_execute_plan(plan, Values, Nulls, false, tcount);
351 * SPI_execute_snapshot -- identical to SPI_execute_plan, except that we allow
352 * the caller to specify exactly which snapshots to use. This is currently
353 * not documented in spi.sgml because it is only intended for use by RI
356 * Passing snapshot == InvalidSnapshot will select the normal behavior of
357 * fetching a new snapshot for each query.
360 SPI_execute_snapshot(void *plan,
361 Datum *Values, const char *Nulls,
362 Snapshot snapshot, Snapshot crosscheck_snapshot,
363 bool read_only, long tcount)
367 if (plan == NULL || tcount < 0)
368 return SPI_ERROR_ARGUMENT;
370 if (((_SPI_plan *) plan)->nargs > 0 && Values == NULL)
371 return SPI_ERROR_PARAM;
373 res = _SPI_begin_call(true);
377 res = _SPI_execute_plan((_SPI_plan *) plan,
379 snapshot, crosscheck_snapshot,
387 SPI_prepare(const char *src, int nargs, Oid *argtypes)
392 if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
394 SPI_result = SPI_ERROR_ARGUMENT;
398 SPI_result = _SPI_begin_call(true);
402 plan.plancxt = NULL; /* doesn't have own context */
405 plan.argtypes = argtypes;
407 _SPI_prepare_plan(src, &plan);
409 /* copy plan to procedure context */
410 result = _SPI_copy_plan(&plan, _SPI_CPLAN_PROCXT);
414 return (void *) result;
418 SPI_saveplan(void *plan)
424 SPI_result = SPI_ERROR_ARGUMENT;
428 SPI_result = _SPI_begin_call(false); /* don't change context */
432 newplan = _SPI_copy_plan((_SPI_plan *) plan, _SPI_CPLAN_TOPCXT);
437 return (void *) newplan;
441 SPI_freeplan(void *plan)
443 _SPI_plan *spiplan = (_SPI_plan *) plan;
446 return SPI_ERROR_ARGUMENT;
448 MemoryContextDelete(spiplan->plancxt);
453 SPI_copytuple(HeapTuple tuple)
455 MemoryContext oldcxt = NULL;
460 SPI_result = SPI_ERROR_ARGUMENT;
464 if (_SPI_curid + 1 == _SPI_connected) /* connected */
466 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
467 elog(ERROR, "SPI stack corrupted");
468 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
471 ctuple = heap_copytuple(tuple);
474 MemoryContextSwitchTo(oldcxt);
480 SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
482 MemoryContext oldcxt = NULL;
483 HeapTupleHeader dtup;
485 if (tuple == NULL || tupdesc == NULL)
487 SPI_result = SPI_ERROR_ARGUMENT;
491 /* For RECORD results, make sure a typmod has been assigned */
492 if (tupdesc->tdtypeid == RECORDOID &&
493 tupdesc->tdtypmod < 0)
494 assign_record_type_typmod(tupdesc);
496 if (_SPI_curid + 1 == _SPI_connected) /* connected */
498 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
499 elog(ERROR, "SPI stack corrupted");
500 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
503 dtup = (HeapTupleHeader) palloc(tuple->t_len);
504 memcpy((char *) dtup, (char *) tuple->t_data, tuple->t_len);
506 HeapTupleHeaderSetDatumLength(dtup, tuple->t_len);
507 HeapTupleHeaderSetTypeId(dtup, tupdesc->tdtypeid);
508 HeapTupleHeaderSetTypMod(dtup, tupdesc->tdtypmod);
511 MemoryContextSwitchTo(oldcxt);
517 SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
518 Datum *Values, const char *Nulls)
520 MemoryContext oldcxt = NULL;
522 int numberOfAttributes;
527 if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
529 SPI_result = SPI_ERROR_ARGUMENT;
533 if (_SPI_curid + 1 == _SPI_connected) /* connected */
535 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
536 elog(ERROR, "SPI stack corrupted");
537 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
540 numberOfAttributes = rel->rd_att->natts;
541 v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
542 n = (char *) palloc(numberOfAttributes * sizeof(char));
544 /* fetch old values and nulls */
545 heap_deformtuple(tuple, rel->rd_att, v, n);
547 /* replace values and nulls */
548 for (i = 0; i < natts; i++)
550 if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
552 v[attnum[i] - 1] = Values[i];
553 n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? 'n' : ' ';
556 if (i == natts) /* no errors in *attnum */
558 mtuple = heap_formtuple(rel->rd_att, v, n);
561 * copy the identification info of the old tuple: t_ctid, t_self,
564 mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
565 mtuple->t_self = tuple->t_self;
566 mtuple->t_tableOid = tuple->t_tableOid;
567 if (rel->rd_att->tdhasoid)
568 HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
573 SPI_result = SPI_ERROR_NOATTRIBUTE;
580 MemoryContextSwitchTo(oldcxt);
586 SPI_fnumber(TupleDesc tupdesc, const char *fname)
589 Form_pg_attribute sysatt;
591 for (res = 0; res < tupdesc->natts; res++)
593 if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0)
597 sysatt = SystemAttributeByName(fname, true /* "oid" will be accepted */ );
599 return sysatt->attnum;
601 /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
602 return SPI_ERROR_NOATTRIBUTE;
606 SPI_fname(TupleDesc tupdesc, int fnumber)
608 Form_pg_attribute att;
612 if (fnumber > tupdesc->natts || fnumber == 0 ||
613 fnumber <= FirstLowInvalidHeapAttributeNumber)
615 SPI_result = SPI_ERROR_NOATTRIBUTE;
620 att = tupdesc->attrs[fnumber - 1];
622 att = SystemAttributeDefinition(fnumber, true);
624 return pstrdup(NameStr(att->attname));
628 SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
640 if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||
641 fnumber <= FirstLowInvalidHeapAttributeNumber)
643 SPI_result = SPI_ERROR_NOATTRIBUTE;
647 origval = heap_getattr(tuple, fnumber, tupdesc, &isnull);
652 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
654 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
656 getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
659 * If we have a toasted datum, forcibly detoast it here to avoid
660 * memory leakage inside the type's output routine.
663 val = PointerGetDatum(PG_DETOAST_DATUM(origval));
667 result = OidFunctionCall1(foutoid,
670 /* Clean up detoasted copy, if any */
672 pfree(DatumGetPointer(val));
674 return DatumGetCString(result);
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;
821 List *qtlist = spiplan->qtlist;
822 List *ptlist = spiplan->ptlist;
825 ParamListInfo paramLI;
827 MemoryContext oldcontext;
831 /* Ensure that the plan contains only one query */
832 if (list_length(ptlist) != 1 || list_length(qtlist) != 1)
834 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
835 errmsg("cannot open multi-query plan as cursor")));
836 queryTree = (Query *) linitial((List *) linitial(qtlist));
837 planTree = (Plan *) linitial(ptlist);
839 /* Must be a query that returns tuples */
840 switch (queryTree->commandType)
843 if (queryTree->into != NULL)
845 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
846 errmsg("cannot open SELECT INTO query as cursor")));
849 if (!UtilityReturnsTuples(queryTree->utilityStmt))
851 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
852 errmsg("cannot open non-SELECT query as cursor")));
856 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
857 errmsg("cannot open non-SELECT query as cursor")));
861 /* Reset SPI result */
864 _SPI_current->processed = 0;
865 _SPI_current->tuptable = NULL;
867 /* Create the portal */
868 if (name == NULL || name[0] == '\0')
870 /* Use a random nonconflicting name */
871 portal = CreateNewPortal();
875 /* In this path, error if portal of same name already exists */
876 portal = CreatePortal(name, false, false);
879 /* Switch to portals memory and copy the parsetree and plan to there */
880 oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
881 queryTree = copyObject(queryTree);
882 planTree = copyObject(planTree);
884 /* If the plan has parameters, set them up */
885 if (spiplan->nargs > 0)
887 paramLI = (ParamListInfo) palloc0((spiplan->nargs + 1) *
888 sizeof(ParamListInfoData));
890 for (k = 0; k < spiplan->nargs; k++)
892 paramLI[k].kind = PARAM_NUM;
893 paramLI[k].id = k + 1;
894 paramLI[k].ptype = spiplan->argtypes[k];
895 paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
896 if (paramLI[k].isnull)
898 /* nulls just copy */
899 paramLI[k].value = Values[k];
903 /* pass-by-ref values must be copied into portal context */
907 get_typlenbyval(spiplan->argtypes[k],
908 ¶mTypLen, ¶mTypByVal);
909 paramLI[k].value = datumCopy(Values[k],
910 paramTypByVal, paramTypLen);
913 paramLI[k].kind = PARAM_INVALID;
921 PortalDefineQuery(portal,
922 NULL, /* unfortunately don't have sourceText */
923 "SELECT", /* nor the raw parse tree... */
924 list_make1(queryTree),
925 list_make1(planTree),
926 PortalGetHeapMemory(portal));
928 MemoryContextSwitchTo(oldcontext);
931 * Set up options for portal.
933 portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL);
934 if (planTree == NULL || ExecSupportsBackwardScan(planTree))
935 portal->cursorOptions |= CURSOR_OPT_SCROLL;
937 portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
940 * Set up the snapshot to use. (PortalStart will do CopySnapshot,
941 * so we skip that here.)
944 snapshot = ActiveSnapshot;
947 CommandCounterIncrement();
948 snapshot = GetTransactionSnapshot();
952 * Start portal execution.
954 PortalStart(portal, paramLI, snapshot);
956 Assert(portal->strategy == PORTAL_ONE_SELECT ||
957 portal->strategy == PORTAL_UTIL_SELECT);
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(SPI, NULL));
986 /* we know that the SPI 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 originates from normal SELECT (i.e.
1048 * *not* a SELECT ... INTO). In essence, the result indicates
1049 * 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;
1060 if (spiplan == NULL)
1062 SPI_result = SPI_ERROR_ARGUMENT;
1066 qtlist = spiplan->qtlist;
1067 if (list_length(spiplan->ptlist) == 1 && list_length(qtlist) == 1)
1069 Query *queryTree = (Query *) linitial((List *) linitial(qtlist));
1071 if (queryTree->commandType == CMD_SELECT && queryTree->into == NULL)
1078 * SPI_result_code_string --- convert any SPI return code to a string
1080 * This is often useful in error messages. Most callers will probably
1081 * only pass negative (error-case) codes, but for generality we recognize
1082 * the success codes too.
1085 SPI_result_code_string(int code)
1087 static char buf[64];
1091 case SPI_ERROR_CONNECT:
1092 return "SPI_ERROR_CONNECT";
1093 case SPI_ERROR_COPY:
1094 return "SPI_ERROR_COPY";
1095 case SPI_ERROR_OPUNKNOWN:
1096 return "SPI_ERROR_OPUNKNOWN";
1097 case SPI_ERROR_UNCONNECTED:
1098 return "SPI_ERROR_UNCONNECTED";
1099 case SPI_ERROR_CURSOR:
1100 return "SPI_ERROR_CURSOR";
1101 case SPI_ERROR_ARGUMENT:
1102 return "SPI_ERROR_ARGUMENT";
1103 case SPI_ERROR_PARAM:
1104 return "SPI_ERROR_PARAM";
1105 case SPI_ERROR_TRANSACTION:
1106 return "SPI_ERROR_TRANSACTION";
1107 case SPI_ERROR_NOATTRIBUTE:
1108 return "SPI_ERROR_NOATTRIBUTE";
1109 case SPI_ERROR_NOOUTFUNC:
1110 return "SPI_ERROR_NOOUTFUNC";
1111 case SPI_ERROR_TYPUNKNOWN:
1112 return "SPI_ERROR_TYPUNKNOWN";
1113 case SPI_OK_CONNECT:
1114 return "SPI_OK_CONNECT";
1116 return "SPI_OK_FINISH";
1118 return "SPI_OK_FETCH";
1119 case SPI_OK_UTILITY:
1120 return "SPI_OK_UTILITY";
1122 return "SPI_OK_SELECT";
1123 case SPI_OK_SELINTO:
1124 return "SPI_OK_SELINTO";
1126 return "SPI_OK_INSERT";
1128 return "SPI_OK_DELETE";
1130 return "SPI_OK_UPDATE";
1132 return "SPI_OK_CURSOR";
1134 /* Unrecognized code ... return something useful ... */
1135 sprintf(buf, "Unrecognized SPI code %d", code);
1139 /* =================== private functions =================== */
1143 * Initialize to receive tuples from Executor into SPITupleTable
1144 * of current SPI procedure
1147 spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
1149 SPITupleTable *tuptable;
1150 MemoryContext oldcxt;
1151 MemoryContext tuptabcxt;
1154 * When called by Executor _SPI_curid expected to be equal to
1157 if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1158 elog(ERROR, "improper call to spi_dest_startup");
1159 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1160 elog(ERROR, "SPI stack corrupted");
1162 if (_SPI_current->tuptable != NULL)
1163 elog(ERROR, "improper call to spi_dest_startup");
1165 oldcxt = _SPI_procmem(); /* switch to procedure memory context */
1167 tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,
1169 ALLOCSET_DEFAULT_MINSIZE,
1170 ALLOCSET_DEFAULT_INITSIZE,
1171 ALLOCSET_DEFAULT_MAXSIZE);
1172 MemoryContextSwitchTo(tuptabcxt);
1174 _SPI_current->tuptable = tuptable = (SPITupleTable *)
1175 palloc(sizeof(SPITupleTable));
1176 tuptable->tuptabcxt = tuptabcxt;
1177 tuptable->alloced = tuptable->free = 128;
1178 tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
1179 tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
1181 MemoryContextSwitchTo(oldcxt);
1186 * store tuple retrieved by Executor into SPITupleTable
1187 * of current SPI procedure
1190 spi_printtup(TupleTableSlot *slot, DestReceiver *self)
1192 SPITupleTable *tuptable;
1193 MemoryContext oldcxt;
1196 * When called by Executor _SPI_curid expected to be equal to
1199 if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1200 elog(ERROR, "improper call to spi_printtup");
1201 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1202 elog(ERROR, "SPI stack corrupted");
1204 tuptable = _SPI_current->tuptable;
1205 if (tuptable == NULL)
1206 elog(ERROR, "improper call to spi_printtup");
1208 oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
1210 if (tuptable->free == 0)
1212 tuptable->free = 256;
1213 tuptable->alloced += tuptable->free;
1214 tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
1215 tuptable->alloced * sizeof(HeapTuple));
1218 tuptable->vals[tuptable->alloced - tuptable->free] =
1219 ExecCopySlotTuple(slot);
1222 MemoryContextSwitchTo(oldcxt);
1230 * Parse and plan a querystring.
1232 * At entry, plan->argtypes and plan->nargs must be valid.
1234 * Query and plan lists are stored into *plan.
1237 _SPI_prepare_plan(const char *src, _SPI_plan *plan)
1239 List *raw_parsetree_list;
1240 List *query_list_list;
1242 ListCell *list_item;
1243 ErrorContextCallback spierrcontext;
1244 Oid *argtypes = plan->argtypes;
1245 int nargs = plan->nargs;
1248 * Increment CommandCounter to see changes made by now. We must do
1249 * this to be sure of seeing any schema changes made by a just-preceding
1250 * SPI command. (But we don't bother advancing the snapshot, since the
1251 * planner generally operates under SnapshotNow rules anyway.)
1253 CommandCounterIncrement();
1256 * Setup error traceback support for ereport()
1258 spierrcontext.callback = _SPI_error_callback;
1259 spierrcontext.arg = (void *) src;
1260 spierrcontext.previous = error_context_stack;
1261 error_context_stack = &spierrcontext;
1264 * Parse the request string into a list of raw parse trees.
1266 raw_parsetree_list = pg_parse_query(src);
1269 * Do parse analysis and rule rewrite for each raw parsetree.
1271 * We save the querytrees from each raw parsetree as a separate
1272 * sublist. This allows _SPI_execute_plan() to know where the
1273 * boundaries between original queries fall.
1275 query_list_list = NIL;
1278 foreach(list_item, raw_parsetree_list)
1280 Node *parsetree = (Node *) lfirst(list_item);
1283 query_list = pg_analyze_and_rewrite(parsetree, argtypes, nargs);
1285 query_list_list = lappend(query_list_list, query_list);
1287 plan_list = list_concat(plan_list,
1288 pg_plan_queries(query_list, NULL, false));
1291 plan->qtlist = query_list_list;
1292 plan->ptlist = plan_list;
1295 * Pop the error context stack
1297 error_context_stack = spierrcontext.previous;
1301 * Execute the given plan with the given parameter values
1303 * snapshot: query snapshot to use, or InvalidSnapshot for the normal
1304 * behavior of taking a new snapshot for each query.
1305 * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
1306 * read_only: TRUE for read-only execution (no CommandCounterIncrement)
1307 * tcount: execution tuple-count limit, or 0 for none
1310 _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
1311 Snapshot snapshot, Snapshot crosscheck_snapshot,
1312 bool read_only, long tcount)
1314 volatile int res = 0;
1315 Snapshot saveActiveSnapshot;
1317 /* Be sure to restore ActiveSnapshot on error exit */
1318 saveActiveSnapshot = ActiveSnapshot;
1321 List *query_list_list = plan->qtlist;
1322 ListCell *plan_list_item = list_head(plan->ptlist);
1323 ListCell *query_list_list_item;
1324 ErrorContextCallback spierrcontext;
1325 int nargs = plan->nargs;
1326 ParamListInfo paramLI;
1328 /* Convert parameters to form wanted by executor */
1333 paramLI = (ParamListInfo)
1334 palloc0((nargs + 1) * sizeof(ParamListInfoData));
1336 for (k = 0; k < nargs; k++)
1338 paramLI[k].kind = PARAM_NUM;
1339 paramLI[k].id = k + 1;
1340 paramLI[k].ptype = plan->argtypes[k];
1341 paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
1342 paramLI[k].value = Values[k];
1344 paramLI[k].kind = PARAM_INVALID;
1349 /* Reset state (only needed in case string is empty) */
1351 SPI_lastoid = InvalidOid;
1352 SPI_tuptable = NULL;
1353 _SPI_current->tuptable = NULL;
1356 * Setup error traceback support for ereport()
1358 spierrcontext.callback = _SPI_error_callback;
1359 spierrcontext.arg = (void *) plan->query;
1360 spierrcontext.previous = error_context_stack;
1361 error_context_stack = &spierrcontext;
1363 foreach(query_list_list_item, query_list_list)
1365 List *query_list = lfirst(query_list_list_item);
1366 ListCell *query_list_item;
1368 /* Reset state for each original parsetree */
1369 /* (at most one of its querytrees will be marked canSetTag) */
1371 SPI_lastoid = InvalidOid;
1372 SPI_tuptable = NULL;
1373 _SPI_current->tuptable = NULL;
1375 foreach(query_list_item, query_list)
1377 Query *queryTree = (Query *) lfirst(query_list_item);
1382 planTree = lfirst(plan_list_item);
1383 plan_list_item = lnext(plan_list_item);
1385 if (queryTree->commandType == CMD_UTILITY)
1387 if (IsA(queryTree->utilityStmt, CopyStmt))
1389 CopyStmt *stmt = (CopyStmt *) queryTree->utilityStmt;
1391 if (stmt->filename == NULL)
1393 res = SPI_ERROR_COPY;
1397 else if (IsA(queryTree->utilityStmt, DeclareCursorStmt) ||
1398 IsA(queryTree->utilityStmt, ClosePortalStmt) ||
1399 IsA(queryTree->utilityStmt, FetchStmt))
1401 res = SPI_ERROR_CURSOR;
1404 else if (IsA(queryTree->utilityStmt, TransactionStmt))
1406 res = SPI_ERROR_TRANSACTION;
1411 if (read_only && !QueryIsReadOnly(queryTree))
1413 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1414 /* translator: %s is a SQL statement name */
1415 errmsg("%s is not allowed in a non-volatile function",
1416 CreateQueryTag(queryTree))));
1418 * If not read-only mode, advance the command counter before
1422 CommandCounterIncrement();
1424 dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None,
1427 if (snapshot == InvalidSnapshot)
1430 * Default read_only behavior is to use the entry-time
1431 * ActiveSnapshot; if read-write, grab a full new snap.
1434 ActiveSnapshot = CopySnapshot(saveActiveSnapshot);
1436 ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
1441 * We interpret read_only with a specified snapshot to be
1442 * exactly that snapshot, but read-write means use the
1443 * snap with advancing of command ID.
1445 ActiveSnapshot = CopySnapshot(snapshot);
1447 ActiveSnapshot->curcid = GetCurrentCommandId();
1450 if (queryTree->commandType == CMD_UTILITY)
1452 ProcessUtility(queryTree->utilityStmt, paramLI,
1454 res = SPI_OK_UTILITY;
1458 qdesc = CreateQueryDesc(queryTree, planTree,
1460 crosscheck_snapshot,
1463 res = _SPI_pquery(qdesc,
1464 queryTree->canSetTag ? tcount : 0);
1465 FreeQueryDesc(qdesc);
1467 FreeSnapshot(ActiveSnapshot);
1468 ActiveSnapshot = NULL;
1469 /* we know that the receiver doesn't need a destroy call */
1478 * Pop the error context stack
1480 error_context_stack = spierrcontext.previous;
1484 /* Restore global vars and propagate error */
1485 ActiveSnapshot = saveActiveSnapshot;
1490 ActiveSnapshot = saveActiveSnapshot;
1496 _SPI_pquery(QueryDesc *queryDesc, long tcount)
1498 int operation = queryDesc->operation;
1505 res = SPI_OK_SELECT;
1506 if (queryDesc->parsetree->into != NULL) /* select into table */
1508 res = SPI_OK_SELINTO;
1509 queryDesc->dest = None_Receiver; /* don't output results */
1513 res = SPI_OK_INSERT;
1516 res = SPI_OK_DELETE;
1519 res = SPI_OK_UPDATE;
1522 return SPI_ERROR_OPUNKNOWN;
1525 #ifdef SPI_EXECUTOR_STATS
1526 if (ShowExecutorStats)
1530 AfterTriggerBeginQuery();
1532 ExecutorStart(queryDesc, false);
1534 ExecutorRun(queryDesc, ForwardScanDirection, tcount);
1536 _SPI_current->processed = queryDesc->estate->es_processed;
1537 save_lastoid = queryDesc->estate->es_lastoid;
1539 if (operation == CMD_SELECT && queryDesc->dest->mydest == SPI)
1541 if (_SPI_checktuples())
1542 elog(ERROR, "consistency check on SPI tuple count failed");
1545 /* Take care of any queued AFTER triggers */
1546 AfterTriggerEndQuery(queryDesc->estate);
1548 ExecutorEnd(queryDesc);
1550 if (queryDesc->dest->mydest == SPI)
1552 SPI_processed = _SPI_current->processed;
1553 SPI_lastoid = save_lastoid;
1554 SPI_tuptable = _SPI_current->tuptable;
1556 else if (res == SPI_OK_SELECT)
1558 /* Don't return SPI_OK_SELECT if we discarded the result */
1559 res = SPI_OK_UTILITY;
1562 #ifdef SPI_EXECUTOR_STATS
1563 if (ShowExecutorStats)
1564 ShowUsage("SPI EXECUTOR STATS");
1571 * _SPI_error_callback
1573 * Add context information when a query invoked via SPI fails
1576 _SPI_error_callback(void *arg)
1578 const char *query = (const char *) arg;
1579 int syntaxerrposition;
1582 * If there is a syntax error position, convert to internal syntax
1583 * error; otherwise treat the query as an item of context stack
1585 syntaxerrposition = geterrposition();
1586 if (syntaxerrposition > 0)
1589 internalerrposition(syntaxerrposition);
1590 internalerrquery(query);
1593 errcontext("SQL statement \"%s\"", query);
1597 * _SPI_cursor_operation()
1599 * Do a FETCH or MOVE in a cursor
1602 _SPI_cursor_operation(Portal portal, bool forward, long count,
1607 /* Check that the portal is valid */
1608 if (!PortalIsValid(portal))
1609 elog(ERROR, "invalid portal in SPI cursor operation");
1611 /* Push the SPI stack */
1612 if (_SPI_begin_call(true) < 0)
1613 elog(ERROR, "SPI cursor operation called while not connected");
1615 /* Reset the SPI result */
1617 SPI_tuptable = NULL;
1618 _SPI_current->processed = 0;
1619 _SPI_current->tuptable = NULL;
1621 /* Run the cursor */
1622 nfetched = PortalRunFetch(portal,
1623 forward ? FETCH_FORWARD : FETCH_BACKWARD,
1628 * Think not to combine this store with the preceding function call.
1629 * If the portal contains calls to functions that use SPI, then
1630 * SPI_stack is likely to move around while the portal runs. When
1631 * control returns, _SPI_current will point to the correct stack
1632 * entry... but the pointer may be different than it was beforehand.
1633 * So we must be sure to re-fetch the pointer after the function call
1636 _SPI_current->processed = nfetched;
1638 if (dest->mydest == SPI && _SPI_checktuples())
1639 elog(ERROR, "consistency check on SPI tuple count failed");
1641 /* Put the result into place for access by caller */
1642 SPI_processed = _SPI_current->processed;
1643 SPI_tuptable = _SPI_current->tuptable;
1645 /* Pop the SPI stack */
1646 _SPI_end_call(true);
1650 static MemoryContext
1653 return MemoryContextSwitchTo(_SPI_current->execCxt);
1656 static MemoryContext
1659 return MemoryContextSwitchTo(_SPI_current->procCxt);
1663 * _SPI_begin_call: begin a SPI operation within a connected procedure
1666 _SPI_begin_call(bool execmem)
1668 if (_SPI_curid + 1 != _SPI_connected)
1669 return SPI_ERROR_UNCONNECTED;
1671 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1672 elog(ERROR, "SPI stack corrupted");
1674 if (execmem) /* switch to the Executor memory context */
1681 * _SPI_end_call: end a SPI operation within a connected procedure
1683 * Note: this currently has no failure return cases, so callers don't check
1686 _SPI_end_call(bool procmem)
1689 * We're returning to procedure where _SPI_curid == _SPI_connected - 1
1693 if (procmem) /* switch to the procedure memory context */
1696 /* and free Executor memory */
1697 MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
1704 _SPI_checktuples(void)
1706 uint32 processed = _SPI_current->processed;
1707 SPITupleTable *tuptable = _SPI_current->tuptable;
1708 bool failed = false;
1710 if (tuptable == NULL) /* spi_dest_startup was not called */
1712 else if (processed != (tuptable->alloced - tuptable->free))
1719 _SPI_copy_plan(_SPI_plan *plan, int location)
1722 MemoryContext oldcxt;
1723 MemoryContext plancxt;
1724 MemoryContext parentcxt;
1726 /* Determine correct parent for the plan's memory context */
1727 if (location == _SPI_CPLAN_PROCXT)
1728 parentcxt = _SPI_current->procCxt;
1729 else if (location == _SPI_CPLAN_TOPCXT)
1730 parentcxt = TopMemoryContext;
1731 else /* (this case not currently used) */
1732 parentcxt = CurrentMemoryContext;
1735 * Create a memory context for the plan. We don't expect the plan to
1736 * be very large, so use smaller-than-default alloc parameters.
1738 plancxt = AllocSetContextCreate(parentcxt,
1740 ALLOCSET_SMALL_MINSIZE,
1741 ALLOCSET_SMALL_INITSIZE,
1742 ALLOCSET_SMALL_MAXSIZE);
1743 oldcxt = MemoryContextSwitchTo(plancxt);
1745 /* Copy the SPI plan into its own context */
1746 newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
1747 newplan->plancxt = plancxt;
1748 newplan->query = pstrdup(plan->query);
1749 newplan->qtlist = (List *) copyObject(plan->qtlist);
1750 newplan->ptlist = (List *) copyObject(plan->ptlist);
1751 newplan->nargs = plan->nargs;
1752 if (plan->nargs > 0)
1754 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
1755 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
1758 newplan->argtypes = NULL;
1760 MemoryContextSwitchTo(oldcxt);