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.133.4.1 2005-02-10 20:36:48 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 "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, int tcount);
44
static int _SPI_pquery(QueryDesc *queryDesc, int tcount);
46
static void _SPI_error_callback(void *arg);
48
static void _SPI_cursor_operation(Portal portal, bool forward, int 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 querystring */
283
SPI_execute(const char *src, bool read_only, int 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, int 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, int 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, int 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, int 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)
642
if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||
643
fnumber <= FirstLowInvalidHeapAttributeNumber)
645
SPI_result = SPI_ERROR_NOATTRIBUTE;
649
origval = heap_getattr(tuple, fnumber, tupdesc, &isnull);
655
typoid = tupdesc->attrs[fnumber - 1]->atttypid;
656
typmod = tupdesc->attrs[fnumber - 1]->atttypmod;
660
typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
664
getTypeOutputInfo(typoid, &foutoid, &typioparam, &typisvarlena);
667
* If we have a toasted datum, forcibly detoast it here to avoid
668
* memory leakage inside the type's output routine.
671
val = PointerGetDatum(PG_DETOAST_DATUM(origval));
675
result = OidFunctionCall3(foutoid,
677
ObjectIdGetDatum(typioparam),
678
Int32GetDatum(typmod));
680
/* Clean up detoasted copy, if any */
682
pfree(DatumGetPointer(val));
684
return DatumGetCString(result);
688
SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
692
if (fnumber > tuple->t_data->t_natts || fnumber == 0 ||
693
fnumber <= FirstLowInvalidHeapAttributeNumber)
695
SPI_result = SPI_ERROR_NOATTRIBUTE;
700
return heap_getattr(tuple, fnumber, tupdesc, isnull);
704
SPI_gettype(TupleDesc tupdesc, int fnumber)
712
if (fnumber > tupdesc->natts || fnumber == 0 ||
713
fnumber <= FirstLowInvalidHeapAttributeNumber)
715
SPI_result = SPI_ERROR_NOATTRIBUTE;
720
typoid = tupdesc->attrs[fnumber - 1]->atttypid;
722
typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
724
typeTuple = SearchSysCache(TYPEOID,
725
ObjectIdGetDatum(typoid),
728
if (!HeapTupleIsValid(typeTuple))
730
SPI_result = SPI_ERROR_TYPUNKNOWN;
734
result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
735
ReleaseSysCache(typeTuple);
740
SPI_gettypeid(TupleDesc tupdesc, int fnumber)
744
if (fnumber > tupdesc->natts || fnumber == 0 ||
745
fnumber <= FirstLowInvalidHeapAttributeNumber)
747
SPI_result = SPI_ERROR_NOATTRIBUTE;
752
return tupdesc->attrs[fnumber - 1]->atttypid;
754
return (SystemAttributeDefinition(fnumber, true))->atttypid;
758
SPI_getrelname(Relation rel)
760
return pstrdup(RelationGetRelationName(rel));
764
SPI_palloc(Size size)
766
MemoryContext oldcxt = NULL;
769
if (_SPI_curid + 1 == _SPI_connected) /* connected */
771
if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
772
elog(ERROR, "SPI stack corrupted");
773
oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
776
pointer = palloc(size);
779
MemoryContextSwitchTo(oldcxt);
785
SPI_repalloc(void *pointer, Size size)
787
/* No longer need to worry which context chunk was in... */
788
return repalloc(pointer, size);
792
SPI_pfree(void *pointer)
794
/* No longer need to worry which context chunk was in... */
799
SPI_freetuple(HeapTuple tuple)
801
/* No longer need to worry which context tuple was in... */
802
heap_freetuple(tuple);
806
SPI_freetuptable(SPITupleTable *tuptable)
808
if (tuptable != NULL)
809
MemoryContextDelete(tuptable->tuptabcxt);
817
* Open a prepared SPI plan as a portal
820
SPI_cursor_open(const char *name, void *plan,
821
Datum *Values, const char *Nulls,
824
_SPI_plan *spiplan = (_SPI_plan *) plan;
825
List *qtlist = spiplan->qtlist;
826
List *ptlist = spiplan->ptlist;
829
ParamListInfo paramLI;
831
MemoryContext oldcontext;
835
/* Ensure that the plan contains only one query */
836
if (list_length(ptlist) != 1 || list_length(qtlist) != 1)
838
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
839
errmsg("cannot open multi-query plan as cursor")));
840
queryTree = (Query *) linitial((List *) linitial(qtlist));
841
planTree = (Plan *) linitial(ptlist);
843
/* Must be a query that returns tuples */
844
switch (queryTree->commandType)
847
if (queryTree->into != NULL)
849
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
850
errmsg("cannot open SELECT INTO query as cursor")));
853
if (!UtilityReturnsTuples(queryTree->utilityStmt))
855
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
856
errmsg("cannot open non-SELECT query as cursor")));
860
(errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
861
errmsg("cannot open non-SELECT query as cursor")));
865
/* Reset SPI result */
868
_SPI_current->processed = 0;
869
_SPI_current->tuptable = NULL;
871
/* Create the portal */
872
if (name == NULL || name[0] == '\0')
874
/* Use a random nonconflicting name */
875
portal = CreateNewPortal();
879
/* In this path, error if portal of same name already exists */
880
portal = CreatePortal(name, false, false);
883
/* Switch to portals memory and copy the parsetree and plan to there */
884
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
885
queryTree = copyObject(queryTree);
886
planTree = copyObject(planTree);
888
/* If the plan has parameters, set them up */
889
if (spiplan->nargs > 0)
891
paramLI = (ParamListInfo) palloc0((spiplan->nargs + 1) *
892
sizeof(ParamListInfoData));
894
for (k = 0; k < spiplan->nargs; k++)
896
paramLI[k].kind = PARAM_NUM;
897
paramLI[k].id = k + 1;
898
paramLI[k].ptype = spiplan->argtypes[k];
899
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
900
if (paramLI[k].isnull)
902
/* nulls just copy */
903
paramLI[k].value = Values[k];
907
/* pass-by-ref values must be copied into portal context */
911
get_typlenbyval(spiplan->argtypes[k],
912
¶mTypLen, ¶mTypByVal);
913
paramLI[k].value = datumCopy(Values[k],
914
paramTypByVal, paramTypLen);
917
paramLI[k].kind = PARAM_INVALID;
925
PortalDefineQuery(portal,
926
NULL, /* unfortunately don't have sourceText */
927
"SELECT", /* nor the raw parse tree... */
928
list_make1(queryTree),
929
list_make1(planTree),
930
PortalGetHeapMemory(portal));
932
MemoryContextSwitchTo(oldcontext);
935
* Set up options for portal.
937
portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL);
938
if (planTree == NULL || ExecSupportsBackwardScan(planTree))
939
portal->cursorOptions |= CURSOR_OPT_SCROLL;
941
portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
944
* Set up the snapshot to use. (PortalStart will do CopySnapshot,
945
* so we skip that here.)
948
snapshot = ActiveSnapshot;
951
CommandCounterIncrement();
952
snapshot = GetTransactionSnapshot();
956
* Start portal execution.
958
PortalStart(portal, paramLI, snapshot);
960
Assert(portal->strategy == PORTAL_ONE_SELECT ||
961
portal->strategy == PORTAL_UTIL_SELECT);
963
/* Return the created portal */
971
* Find the portal of an existing open cursor
974
SPI_cursor_find(const char *name)
976
return GetPortalByName(name);
983
* Fetch rows in a cursor
986
SPI_cursor_fetch(Portal portal, bool forward, int count)
988
_SPI_cursor_operation(portal, forward, count,
989
CreateDestReceiver(SPI, NULL));
990
/* we know that the SPI receiver doesn't need a destroy call */
1000
SPI_cursor_move(Portal portal, bool forward, int count)
1002
_SPI_cursor_operation(portal, forward, count, None_Receiver);
1007
* SPI_cursor_close()
1012
SPI_cursor_close(Portal portal)
1014
if (!PortalIsValid(portal))
1015
elog(ERROR, "invalid portal in SPI cursor operation");
1017
PortalDrop(portal, false);
1021
* Returns the Oid representing the type id for argument at argIndex. First
1022
* parameter is at index zero.
1025
SPI_getargtypeid(void *plan, int argIndex)
1027
if (plan == NULL || argIndex < 0 || argIndex >= ((_SPI_plan *) plan)->nargs)
1029
SPI_result = SPI_ERROR_ARGUMENT;
1032
return ((_SPI_plan *) plan)->argtypes[argIndex];
1036
* Returns the number of arguments for the prepared plan.
1039
SPI_getargcount(void *plan)
1043
SPI_result = SPI_ERROR_ARGUMENT;
1046
return ((_SPI_plan *) plan)->nargs;
1050
* Returns true if the plan contains exactly one command
1051
* and that command originates from normal SELECT (i.e.
1052
* *not* a SELECT ... INTO). In essence, the result indicates
1053
* if the command can be used with SPI_cursor_open
1056
* plan A plan previously prepared using SPI_prepare
1059
SPI_is_cursor_plan(void *plan)
1061
_SPI_plan *spiplan = (_SPI_plan *) plan;
1064
if (spiplan == NULL)
1066
SPI_result = SPI_ERROR_ARGUMENT;
1070
qtlist = spiplan->qtlist;
1071
if (list_length(spiplan->ptlist) == 1 && list_length(qtlist) == 1)
1073
Query *queryTree = (Query *) linitial((List *) linitial(qtlist));
1075
if (queryTree->commandType == CMD_SELECT && queryTree->into == NULL)
1082
* SPI_result_code_string --- convert any SPI return code to a string
1084
* This is often useful in error messages. Most callers will probably
1085
* only pass negative (error-case) codes, but for generality we recognize
1086
* the success codes too.
1089
SPI_result_code_string(int code)
1091
static char buf[64];
1095
case SPI_ERROR_CONNECT:
1096
return "SPI_ERROR_CONNECT";
1097
case SPI_ERROR_COPY:
1098
return "SPI_ERROR_COPY";
1099
case SPI_ERROR_OPUNKNOWN:
1100
return "SPI_ERROR_OPUNKNOWN";
1101
case SPI_ERROR_UNCONNECTED:
1102
return "SPI_ERROR_UNCONNECTED";
1103
case SPI_ERROR_CURSOR:
1104
return "SPI_ERROR_CURSOR";
1105
case SPI_ERROR_ARGUMENT:
1106
return "SPI_ERROR_ARGUMENT";
1107
case SPI_ERROR_PARAM:
1108
return "SPI_ERROR_PARAM";
1109
case SPI_ERROR_TRANSACTION:
1110
return "SPI_ERROR_TRANSACTION";
1111
case SPI_ERROR_NOATTRIBUTE:
1112
return "SPI_ERROR_NOATTRIBUTE";
1113
case SPI_ERROR_NOOUTFUNC:
1114
return "SPI_ERROR_NOOUTFUNC";
1115
case SPI_ERROR_TYPUNKNOWN:
1116
return "SPI_ERROR_TYPUNKNOWN";
1117
case SPI_OK_CONNECT:
1118
return "SPI_OK_CONNECT";
1120
return "SPI_OK_FINISH";
1122
return "SPI_OK_FETCH";
1123
case SPI_OK_UTILITY:
1124
return "SPI_OK_UTILITY";
1126
return "SPI_OK_SELECT";
1127
case SPI_OK_SELINTO:
1128
return "SPI_OK_SELINTO";
1130
return "SPI_OK_INSERT";
1132
return "SPI_OK_DELETE";
1134
return "SPI_OK_UPDATE";
1136
return "SPI_OK_CURSOR";
1138
/* Unrecognized code ... return something useful ... */
1139
sprintf(buf, "Unrecognized SPI code %d", code);
1143
/* =================== private functions =================== */
1147
* Initialize to receive tuples from Executor into SPITupleTable
1148
* of current SPI procedure
1151
spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
1153
SPITupleTable *tuptable;
1154
MemoryContext oldcxt;
1155
MemoryContext tuptabcxt;
1158
* When called by Executor _SPI_curid expected to be equal to
1161
if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1162
elog(ERROR, "improper call to spi_dest_startup");
1163
if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1164
elog(ERROR, "SPI stack corrupted");
1166
if (_SPI_current->tuptable != NULL)
1167
elog(ERROR, "improper call to spi_dest_startup");
1169
oldcxt = _SPI_procmem(); /* switch to procedure memory context */
1171
tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,
1173
ALLOCSET_DEFAULT_MINSIZE,
1174
ALLOCSET_DEFAULT_INITSIZE,
1175
ALLOCSET_DEFAULT_MAXSIZE);
1176
MemoryContextSwitchTo(tuptabcxt);
1178
_SPI_current->tuptable = tuptable = (SPITupleTable *)
1179
palloc(sizeof(SPITupleTable));
1180
tuptable->tuptabcxt = tuptabcxt;
1181
tuptable->alloced = tuptable->free = 128;
1182
tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
1183
tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
1185
MemoryContextSwitchTo(oldcxt);
1190
* store tuple retrieved by Executor into SPITupleTable
1191
* of current SPI procedure
1194
spi_printtup(HeapTuple tuple, TupleDesc tupdesc, DestReceiver *self)
1196
SPITupleTable *tuptable;
1197
MemoryContext oldcxt;
1200
* When called by Executor _SPI_curid expected to be equal to
1203
if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
1204
elog(ERROR, "improper call to spi_printtup");
1205
if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1206
elog(ERROR, "SPI stack corrupted");
1208
tuptable = _SPI_current->tuptable;
1209
if (tuptable == NULL)
1210
elog(ERROR, "improper call to spi_printtup");
1212
oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
1214
if (tuptable->free == 0)
1216
tuptable->free = 256;
1217
tuptable->alloced += tuptable->free;
1218
tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
1219
tuptable->alloced * sizeof(HeapTuple));
1222
tuptable->vals[tuptable->alloced - tuptable->free] = heap_copytuple(tuple);
1225
MemoryContextSwitchTo(oldcxt);
1233
* Parse and plan a querystring.
1235
* At entry, plan->argtypes and plan->nargs must be valid.
1237
* Query and plan lists are stored into *plan.
1240
_SPI_prepare_plan(const char *src, _SPI_plan *plan)
1242
List *raw_parsetree_list;
1243
List *query_list_list;
1245
ListCell *list_item;
1246
ErrorContextCallback spierrcontext;
1247
Oid *argtypes = plan->argtypes;
1248
int nargs = plan->nargs;
1251
* Increment CommandCounter to see changes made by now. We must do
1252
* this to be sure of seeing any schema changes made by a just-preceding
1253
* SPI command. (But we don't bother advancing the snapshot, since the
1254
* planner generally operates under SnapshotNow rules anyway.)
1256
CommandCounterIncrement();
1259
* Setup error traceback support for ereport()
1261
spierrcontext.callback = _SPI_error_callback;
1262
spierrcontext.arg = (void *) src;
1263
spierrcontext.previous = error_context_stack;
1264
error_context_stack = &spierrcontext;
1267
* Parse the request string into a list of raw parse trees.
1269
raw_parsetree_list = pg_parse_query(src);
1272
* Do parse analysis and rule rewrite for each raw parsetree.
1274
* We save the querytrees from each raw parsetree as a separate
1275
* sublist. This allows _SPI_execute_plan() to know where the
1276
* boundaries between original queries fall.
1278
query_list_list = NIL;
1281
foreach(list_item, raw_parsetree_list)
1283
Node *parsetree = (Node *) lfirst(list_item);
1286
query_list = pg_analyze_and_rewrite(parsetree, argtypes, nargs);
1288
query_list_list = lappend(query_list_list, query_list);
1290
plan_list = list_concat(plan_list,
1291
pg_plan_queries(query_list, NULL, false));
1294
plan->qtlist = query_list_list;
1295
plan->ptlist = plan_list;
1298
* Pop the error context stack
1300
error_context_stack = spierrcontext.previous;
1304
* Execute the given plan with the given parameter values
1306
* snapshot: query snapshot to use, or InvalidSnapshot for the normal
1307
* behavior of taking a new snapshot for each query.
1308
* crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
1309
* read_only: TRUE for read-only execution (no CommandCounterIncrement)
1310
* tcount: execution tuple-count limit, or 0 for none
1313
_SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
1314
Snapshot snapshot, Snapshot crosscheck_snapshot,
1315
bool read_only, int tcount)
1317
volatile int res = 0;
1318
Snapshot saveActiveSnapshot;
1320
/* Be sure to restore ActiveSnapshot on error exit */
1321
saveActiveSnapshot = ActiveSnapshot;
1324
List *query_list_list = plan->qtlist;
1325
ListCell *plan_list_item = list_head(plan->ptlist);
1326
ListCell *query_list_list_item;
1327
ErrorContextCallback spierrcontext;
1328
int nargs = plan->nargs;
1329
ParamListInfo paramLI;
1331
/* Convert parameters to form wanted by executor */
1336
paramLI = (ParamListInfo)
1337
palloc0((nargs + 1) * sizeof(ParamListInfoData));
1339
for (k = 0; k < nargs; k++)
1341
paramLI[k].kind = PARAM_NUM;
1342
paramLI[k].id = k + 1;
1343
paramLI[k].ptype = plan->argtypes[k];
1344
paramLI[k].isnull = (Nulls && Nulls[k] == 'n');
1345
paramLI[k].value = Values[k];
1347
paramLI[k].kind = PARAM_INVALID;
1352
/* Reset state (only needed in case string is empty) */
1354
SPI_lastoid = InvalidOid;
1355
SPI_tuptable = NULL;
1356
_SPI_current->tuptable = NULL;
1359
* Setup error traceback support for ereport()
1361
spierrcontext.callback = _SPI_error_callback;
1362
spierrcontext.arg = (void *) plan->query;
1363
spierrcontext.previous = error_context_stack;
1364
error_context_stack = &spierrcontext;
1366
foreach(query_list_list_item, query_list_list)
1368
List *query_list = lfirst(query_list_list_item);
1369
ListCell *query_list_item;
1371
/* Reset state for each original parsetree */
1372
/* (at most one of its querytrees will be marked canSetTag) */
1374
SPI_lastoid = InvalidOid;
1375
SPI_tuptable = NULL;
1376
_SPI_current->tuptable = NULL;
1378
foreach(query_list_item, query_list)
1380
Query *queryTree = (Query *) lfirst(query_list_item);
1385
planTree = lfirst(plan_list_item);
1386
plan_list_item = lnext(plan_list_item);
1388
if (queryTree->commandType == CMD_UTILITY)
1390
if (IsA(queryTree->utilityStmt, CopyStmt))
1392
CopyStmt *stmt = (CopyStmt *) queryTree->utilityStmt;
1394
if (stmt->filename == NULL)
1396
res = SPI_ERROR_COPY;
1400
else if (IsA(queryTree->utilityStmt, DeclareCursorStmt) ||
1401
IsA(queryTree->utilityStmt, ClosePortalStmt) ||
1402
IsA(queryTree->utilityStmt, FetchStmt))
1404
res = SPI_ERROR_CURSOR;
1407
else if (IsA(queryTree->utilityStmt, TransactionStmt))
1409
res = SPI_ERROR_TRANSACTION;
1414
if (read_only && !QueryIsReadOnly(queryTree))
1416
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
1417
/* translator: %s is a SQL statement name */
1418
errmsg("%s is not allowed in a non-volatile function",
1419
CreateQueryTag(queryTree))));
1421
* If not read-only mode, advance the command counter before
1425
CommandCounterIncrement();
1427
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None,
1430
if (snapshot == InvalidSnapshot)
1433
* Default read_only behavior is to use the entry-time
1434
* ActiveSnapshot; if read-write, grab a full new snap.
1437
ActiveSnapshot = CopySnapshot(saveActiveSnapshot);
1439
ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
1444
* We interpret read_only with a specified snapshot to be
1445
* exactly that snapshot, but read-write means use the
1446
* snap with advancing of command ID.
1448
ActiveSnapshot = CopySnapshot(snapshot);
1450
ActiveSnapshot->curcid = GetCurrentCommandId();
1453
if (queryTree->commandType == CMD_UTILITY)
1455
ProcessUtility(queryTree->utilityStmt, paramLI,
1457
res = SPI_OK_UTILITY;
1461
qdesc = CreateQueryDesc(queryTree, planTree,
1463
crosscheck_snapshot,
1466
res = _SPI_pquery(qdesc,
1467
queryTree->canSetTag ? tcount : 0);
1468
FreeQueryDesc(qdesc);
1470
FreeSnapshot(ActiveSnapshot);
1471
ActiveSnapshot = NULL;
1472
/* we know that the receiver doesn't need a destroy call */
1481
* Pop the error context stack
1483
error_context_stack = spierrcontext.previous;
1487
/* Restore global vars and propagate error */
1488
ActiveSnapshot = saveActiveSnapshot;
1493
ActiveSnapshot = saveActiveSnapshot;
1499
_SPI_pquery(QueryDesc *queryDesc, int tcount)
1501
int operation = queryDesc->operation;
1508
res = SPI_OK_SELECT;
1509
if (queryDesc->parsetree->into != NULL) /* select into table */
1511
res = SPI_OK_SELINTO;
1512
queryDesc->dest = None_Receiver; /* don't output results */
1516
res = SPI_OK_INSERT;
1519
res = SPI_OK_DELETE;
1522
res = SPI_OK_UPDATE;
1525
return SPI_ERROR_OPUNKNOWN;
1528
#ifdef SPI_EXECUTOR_STATS
1529
if (ShowExecutorStats)
1533
AfterTriggerBeginQuery();
1535
ExecutorStart(queryDesc, false);
1537
ExecutorRun(queryDesc, ForwardScanDirection, (long) tcount);
1539
_SPI_current->processed = queryDesc->estate->es_processed;
1540
save_lastoid = queryDesc->estate->es_lastoid;
1542
if (operation == CMD_SELECT && queryDesc->dest->mydest == SPI)
1544
if (_SPI_checktuples())
1545
elog(ERROR, "consistency check on SPI tuple count failed");
1548
ExecutorEnd(queryDesc);
1550
/* Take care of any queued AFTER triggers */
1551
AfterTriggerEndQuery();
1553
if (queryDesc->dest->mydest == SPI)
1555
SPI_processed = _SPI_current->processed;
1556
SPI_lastoid = save_lastoid;
1557
SPI_tuptable = _SPI_current->tuptable;
1559
else if (res == SPI_OK_SELECT)
1561
/* Don't return SPI_OK_SELECT if we discarded the result */
1562
res = SPI_OK_UTILITY;
1565
#ifdef SPI_EXECUTOR_STATS
1566
if (ShowExecutorStats)
1567
ShowUsage("SPI EXECUTOR STATS");
1574
* _SPI_error_callback
1576
* Add context information when a query invoked via SPI fails
1579
_SPI_error_callback(void *arg)
1581
const char *query = (const char *) arg;
1582
int syntaxerrposition;
1585
* If there is a syntax error position, convert to internal syntax
1586
* error; otherwise treat the query as an item of context stack
1588
syntaxerrposition = geterrposition();
1589
if (syntaxerrposition > 0)
1592
internalerrposition(syntaxerrposition);
1593
internalerrquery(query);
1596
errcontext("SQL statement \"%s\"", query);
1600
* _SPI_cursor_operation()
1602
* Do a FETCH or MOVE in a cursor
1605
_SPI_cursor_operation(Portal portal, bool forward, int count,
1610
/* Check that the portal is valid */
1611
if (!PortalIsValid(portal))
1612
elog(ERROR, "invalid portal in SPI cursor operation");
1614
/* Push the SPI stack */
1615
if (_SPI_begin_call(true) < 0)
1616
elog(ERROR, "SPI cursor operation called while not connected");
1618
/* Reset the SPI result */
1620
SPI_tuptable = NULL;
1621
_SPI_current->processed = 0;
1622
_SPI_current->tuptable = NULL;
1624
/* Run the cursor */
1625
nfetched = PortalRunFetch(portal,
1626
forward ? FETCH_FORWARD : FETCH_BACKWARD,
1631
* Think not to combine this store with the preceding function call.
1632
* If the portal contains calls to functions that use SPI, then
1633
* SPI_stack is likely to move around while the portal runs. When
1634
* control returns, _SPI_current will point to the correct stack
1635
* entry... but the pointer may be different than it was beforehand.
1636
* So we must be sure to re-fetch the pointer after the function call
1639
_SPI_current->processed = nfetched;
1641
if (dest->mydest == SPI && _SPI_checktuples())
1642
elog(ERROR, "consistency check on SPI tuple count failed");
1644
/* Put the result into place for access by caller */
1645
SPI_processed = _SPI_current->processed;
1646
SPI_tuptable = _SPI_current->tuptable;
1648
/* Pop the SPI stack */
1649
_SPI_end_call(true);
1653
static MemoryContext
1656
return MemoryContextSwitchTo(_SPI_current->execCxt);
1659
static MemoryContext
1662
return MemoryContextSwitchTo(_SPI_current->procCxt);
1666
* _SPI_begin_call: begin a SPI operation within a connected procedure
1669
_SPI_begin_call(bool execmem)
1671
if (_SPI_curid + 1 != _SPI_connected)
1672
return SPI_ERROR_UNCONNECTED;
1674
if (_SPI_current != &(_SPI_stack[_SPI_curid]))
1675
elog(ERROR, "SPI stack corrupted");
1677
if (execmem) /* switch to the Executor memory context */
1684
* _SPI_end_call: end a SPI operation within a connected procedure
1686
* Note: this currently has no failure return cases, so callers don't check
1689
_SPI_end_call(bool procmem)
1692
* We're returning to procedure where _SPI_curid == _SPI_connected - 1
1696
if (procmem) /* switch to the procedure memory context */
1699
/* and free Executor memory */
1700
MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
1707
_SPI_checktuples(void)
1709
uint32 processed = _SPI_current->processed;
1710
SPITupleTable *tuptable = _SPI_current->tuptable;
1711
bool failed = false;
1713
if (tuptable == NULL) /* spi_dest_startup was not called */
1715
else if (processed != (tuptable->alloced - tuptable->free))
1722
_SPI_copy_plan(_SPI_plan *plan, int location)
1725
MemoryContext oldcxt;
1726
MemoryContext plancxt;
1727
MemoryContext parentcxt;
1729
/* Determine correct parent for the plan's memory context */
1730
if (location == _SPI_CPLAN_PROCXT)
1731
parentcxt = _SPI_current->procCxt;
1732
else if (location == _SPI_CPLAN_TOPCXT)
1733
parentcxt = TopMemoryContext;
1734
else /* (this case not currently used) */
1735
parentcxt = CurrentMemoryContext;
1738
* Create a memory context for the plan. We don't expect the plan to
1739
* be very large, so use smaller-than-default alloc parameters.
1741
plancxt = AllocSetContextCreate(parentcxt,
1743
ALLOCSET_SMALL_MINSIZE,
1744
ALLOCSET_SMALL_INITSIZE,
1745
ALLOCSET_SMALL_MAXSIZE);
1746
oldcxt = MemoryContextSwitchTo(plancxt);
1748
/* Copy the SPI plan into its own context */
1749
newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
1750
newplan->plancxt = plancxt;
1751
newplan->query = pstrdup(plan->query);
1752
newplan->qtlist = (List *) copyObject(plan->qtlist);
1753
newplan->ptlist = (List *) copyObject(plan->ptlist);
1754
newplan->nargs = plan->nargs;
1755
if (plan->nargs > 0)
1757
newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
1758
memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
1761
newplan->argtypes = NULL;
1763
MemoryContextSwitchTo(oldcxt);