00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "postgres.h"
00016
00017 #include "access/htup_details.h"
00018 #include "access/printtup.h"
00019 #include "access/sysattr.h"
00020 #include "access/xact.h"
00021 #include "catalog/heap.h"
00022 #include "catalog/pg_type.h"
00023 #include "commands/trigger.h"
00024 #include "executor/executor.h"
00025 #include "executor/spi_priv.h"
00026 #include "tcop/pquery.h"
00027 #include "tcop/utility.h"
00028 #include "utils/builtins.h"
00029 #include "utils/datum.h"
00030 #include "utils/lsyscache.h"
00031 #include "utils/memutils.h"
00032 #include "utils/rel.h"
00033 #include "utils/snapmgr.h"
00034 #include "utils/syscache.h"
00035 #include "utils/typcache.h"
00036
00037
00038 uint32 SPI_processed = 0;
00039 Oid SPI_lastoid = InvalidOid;
00040 SPITupleTable *SPI_tuptable = NULL;
00041 int SPI_result;
00042
00043 static _SPI_connection *_SPI_stack = NULL;
00044 static _SPI_connection *_SPI_current = NULL;
00045 static int _SPI_stack_depth = 0;
00046 static int _SPI_connected = -1;
00047 static int _SPI_curid = -1;
00048
00049 static Portal SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
00050 ParamListInfo paramLI, bool read_only);
00051
00052 static void _SPI_prepare_plan(const char *src, SPIPlanPtr plan);
00053
00054 static void _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan);
00055
00056 static int _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
00057 Snapshot snapshot, Snapshot crosscheck_snapshot,
00058 bool read_only, bool fire_triggers, long tcount);
00059
00060 static ParamListInfo _SPI_convert_params(int nargs, Oid *argtypes,
00061 Datum *Values, const char *Nulls);
00062
00063 static int _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount);
00064
00065 static void _SPI_error_callback(void *arg);
00066
00067 static void _SPI_cursor_operation(Portal portal,
00068 FetchDirection direction, long count,
00069 DestReceiver *dest);
00070
00071 static SPIPlanPtr _SPI_make_plan_non_temp(SPIPlanPtr plan);
00072 static SPIPlanPtr _SPI_save_plan(SPIPlanPtr plan);
00073
00074 static int _SPI_begin_call(bool execmem);
00075 static int _SPI_end_call(bool procmem);
00076 static MemoryContext _SPI_execmem(void);
00077 static MemoryContext _SPI_procmem(void);
00078 static bool _SPI_checktuples(void);
00079
00080
00081
00082
00083 int
00084 SPI_connect(void)
00085 {
00086 int newdepth;
00087
00088
00089
00090
00091
00092 if (_SPI_curid != _SPI_connected)
00093 return SPI_ERROR_CONNECT;
00094
00095 if (_SPI_stack == NULL)
00096 {
00097 if (_SPI_connected != -1 || _SPI_stack_depth != 0)
00098 elog(ERROR, "SPI stack corrupted");
00099 newdepth = 16;
00100 _SPI_stack = (_SPI_connection *)
00101 MemoryContextAlloc(TopTransactionContext,
00102 newdepth * sizeof(_SPI_connection));
00103 _SPI_stack_depth = newdepth;
00104 }
00105 else
00106 {
00107 if (_SPI_stack_depth <= 0 || _SPI_stack_depth <= _SPI_connected)
00108 elog(ERROR, "SPI stack corrupted");
00109 if (_SPI_stack_depth == _SPI_connected + 1)
00110 {
00111 newdepth = _SPI_stack_depth * 2;
00112 _SPI_stack = (_SPI_connection *)
00113 repalloc(_SPI_stack,
00114 newdepth * sizeof(_SPI_connection));
00115 _SPI_stack_depth = newdepth;
00116 }
00117 }
00118
00119
00120
00121
00122 _SPI_connected++;
00123 Assert(_SPI_connected >= 0 && _SPI_connected < _SPI_stack_depth);
00124
00125 _SPI_current = &(_SPI_stack[_SPI_connected]);
00126 _SPI_current->processed = 0;
00127 _SPI_current->lastoid = InvalidOid;
00128 _SPI_current->tuptable = NULL;
00129 _SPI_current->procCxt = NULL;
00130 _SPI_current->execCxt = NULL;
00131 _SPI_current->connectSubid = GetCurrentSubTransactionId();
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141 _SPI_current->procCxt = AllocSetContextCreate(TopTransactionContext,
00142 "SPI Proc",
00143 ALLOCSET_DEFAULT_MINSIZE,
00144 ALLOCSET_DEFAULT_INITSIZE,
00145 ALLOCSET_DEFAULT_MAXSIZE);
00146 _SPI_current->execCxt = AllocSetContextCreate(TopTransactionContext,
00147 "SPI Exec",
00148 ALLOCSET_DEFAULT_MINSIZE,
00149 ALLOCSET_DEFAULT_INITSIZE,
00150 ALLOCSET_DEFAULT_MAXSIZE);
00151
00152 _SPI_current->savedcxt = MemoryContextSwitchTo(_SPI_current->procCxt);
00153
00154 return SPI_OK_CONNECT;
00155 }
00156
00157 int
00158 SPI_finish(void)
00159 {
00160 int res;
00161
00162 res = _SPI_begin_call(false);
00163 if (res < 0)
00164 return res;
00165
00166
00167 MemoryContextSwitchTo(_SPI_current->savedcxt);
00168
00169
00170 MemoryContextDelete(_SPI_current->execCxt);
00171 _SPI_current->execCxt = NULL;
00172 MemoryContextDelete(_SPI_current->procCxt);
00173 _SPI_current->procCxt = NULL;
00174
00175
00176
00177
00178
00179 SPI_processed = 0;
00180 SPI_lastoid = InvalidOid;
00181 SPI_tuptable = NULL;
00182
00183
00184
00185
00186
00187
00188 _SPI_connected--;
00189 _SPI_curid--;
00190 if (_SPI_connected == -1)
00191 _SPI_current = NULL;
00192 else
00193 _SPI_current = &(_SPI_stack[_SPI_connected]);
00194
00195 return SPI_OK_FINISH;
00196 }
00197
00198
00199
00200
00201 void
00202 AtEOXact_SPI(bool isCommit)
00203 {
00204
00205
00206
00207
00208
00209 if (isCommit && _SPI_connected != -1)
00210 ereport(WARNING,
00211 (errcode(ERRCODE_WARNING),
00212 errmsg("transaction left non-empty SPI stack"),
00213 errhint("Check for missing \"SPI_finish\" calls.")));
00214
00215 _SPI_current = _SPI_stack = NULL;
00216 _SPI_stack_depth = 0;
00217 _SPI_connected = _SPI_curid = -1;
00218 SPI_processed = 0;
00219 SPI_lastoid = InvalidOid;
00220 SPI_tuptable = NULL;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229 void
00230 AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid)
00231 {
00232 bool found = false;
00233
00234 while (_SPI_connected >= 0)
00235 {
00236 _SPI_connection *connection = &(_SPI_stack[_SPI_connected]);
00237
00238 if (connection->connectSubid != mySubid)
00239 break;
00240
00241 found = true;
00242
00243
00244
00245
00246 if (connection->execCxt)
00247 {
00248 MemoryContextDelete(connection->execCxt);
00249 connection->execCxt = NULL;
00250 }
00251 if (connection->procCxt)
00252 {
00253 MemoryContextDelete(connection->procCxt);
00254 connection->procCxt = NULL;
00255 }
00256
00257
00258
00259
00260
00261
00262 _SPI_connected--;
00263 _SPI_curid = _SPI_connected;
00264 if (_SPI_connected == -1)
00265 _SPI_current = NULL;
00266 else
00267 _SPI_current = &(_SPI_stack[_SPI_connected]);
00268 SPI_processed = 0;
00269 SPI_lastoid = InvalidOid;
00270 SPI_tuptable = NULL;
00271 }
00272
00273 if (found && isCommit)
00274 ereport(WARNING,
00275 (errcode(ERRCODE_WARNING),
00276 errmsg("subtransaction left non-empty SPI stack"),
00277 errhint("Check for missing \"SPI_finish\" calls.")));
00278
00279
00280
00281
00282
00283 if (_SPI_current && !isCommit)
00284 {
00285
00286 MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
00287
00288 SPI_freetuptable(_SPI_current->tuptable);
00289 _SPI_current->tuptable = NULL;
00290 }
00291 }
00292
00293
00294
00295 void
00296 SPI_push(void)
00297 {
00298 _SPI_curid++;
00299 }
00300
00301
00302 void
00303 SPI_pop(void)
00304 {
00305 _SPI_curid--;
00306 }
00307
00308
00309 bool
00310 SPI_push_conditional(void)
00311 {
00312 bool pushed = (_SPI_curid != _SPI_connected);
00313
00314 if (pushed)
00315 {
00316 _SPI_curid++;
00317
00318 Assert(_SPI_curid == _SPI_connected);
00319 }
00320 return pushed;
00321 }
00322
00323
00324 void
00325 SPI_pop_conditional(bool pushed)
00326 {
00327
00328 Assert(_SPI_curid == _SPI_connected);
00329 if (pushed)
00330 _SPI_curid--;
00331 }
00332
00333
00334 void
00335 SPI_restore_connection(void)
00336 {
00337 Assert(_SPI_connected >= 0);
00338 _SPI_curid = _SPI_connected - 1;
00339 }
00340
00341
00342 int
00343 SPI_execute(const char *src, bool read_only, long tcount)
00344 {
00345 _SPI_plan plan;
00346 int res;
00347
00348 if (src == NULL || tcount < 0)
00349 return SPI_ERROR_ARGUMENT;
00350
00351 res = _SPI_begin_call(true);
00352 if (res < 0)
00353 return res;
00354
00355 memset(&plan, 0, sizeof(_SPI_plan));
00356 plan.magic = _SPI_PLAN_MAGIC;
00357 plan.cursor_options = 0;
00358
00359 _SPI_prepare_oneshot_plan(src, &plan);
00360
00361 res = _SPI_execute_plan(&plan, NULL,
00362 InvalidSnapshot, InvalidSnapshot,
00363 read_only, true, tcount);
00364
00365 _SPI_end_call(true);
00366 return res;
00367 }
00368
00369
00370 int
00371 SPI_exec(const char *src, long tcount)
00372 {
00373 return SPI_execute(src, false, tcount);
00374 }
00375
00376
00377 int
00378 SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
00379 bool read_only, long tcount)
00380 {
00381 int res;
00382
00383 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
00384 return SPI_ERROR_ARGUMENT;
00385
00386 if (plan->nargs > 0 && Values == NULL)
00387 return SPI_ERROR_PARAM;
00388
00389 res = _SPI_begin_call(true);
00390 if (res < 0)
00391 return res;
00392
00393 res = _SPI_execute_plan(plan,
00394 _SPI_convert_params(plan->nargs, plan->argtypes,
00395 Values, Nulls),
00396 InvalidSnapshot, InvalidSnapshot,
00397 read_only, true, tcount);
00398
00399 _SPI_end_call(true);
00400 return res;
00401 }
00402
00403
00404 int
00405 SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls, long tcount)
00406 {
00407 return SPI_execute_plan(plan, Values, Nulls, false, tcount);
00408 }
00409
00410
00411 int
00412 SPI_execute_plan_with_paramlist(SPIPlanPtr plan, ParamListInfo params,
00413 bool read_only, long tcount)
00414 {
00415 int res;
00416
00417 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
00418 return SPI_ERROR_ARGUMENT;
00419
00420 res = _SPI_begin_call(true);
00421 if (res < 0)
00422 return res;
00423
00424 res = _SPI_execute_plan(plan, params,
00425 InvalidSnapshot, InvalidSnapshot,
00426 read_only, true, tcount);
00427
00428 _SPI_end_call(true);
00429 return res;
00430 }
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445 int
00446 SPI_execute_snapshot(SPIPlanPtr plan,
00447 Datum *Values, const char *Nulls,
00448 Snapshot snapshot, Snapshot crosscheck_snapshot,
00449 bool read_only, bool fire_triggers, long tcount)
00450 {
00451 int res;
00452
00453 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC || tcount < 0)
00454 return SPI_ERROR_ARGUMENT;
00455
00456 if (plan->nargs > 0 && Values == NULL)
00457 return SPI_ERROR_PARAM;
00458
00459 res = _SPI_begin_call(true);
00460 if (res < 0)
00461 return res;
00462
00463 res = _SPI_execute_plan(plan,
00464 _SPI_convert_params(plan->nargs, plan->argtypes,
00465 Values, Nulls),
00466 snapshot, crosscheck_snapshot,
00467 read_only, fire_triggers, tcount);
00468
00469 _SPI_end_call(true);
00470 return res;
00471 }
00472
00473
00474
00475
00476
00477
00478
00479 int
00480 SPI_execute_with_args(const char *src,
00481 int nargs, Oid *argtypes,
00482 Datum *Values, const char *Nulls,
00483 bool read_only, long tcount)
00484 {
00485 int res;
00486 _SPI_plan plan;
00487 ParamListInfo paramLI;
00488
00489 if (src == NULL || nargs < 0 || tcount < 0)
00490 return SPI_ERROR_ARGUMENT;
00491
00492 if (nargs > 0 && (argtypes == NULL || Values == NULL))
00493 return SPI_ERROR_PARAM;
00494
00495 res = _SPI_begin_call(true);
00496 if (res < 0)
00497 return res;
00498
00499 memset(&plan, 0, sizeof(_SPI_plan));
00500 plan.magic = _SPI_PLAN_MAGIC;
00501 plan.cursor_options = 0;
00502 plan.nargs = nargs;
00503 plan.argtypes = argtypes;
00504 plan.parserSetup = NULL;
00505 plan.parserSetupArg = NULL;
00506
00507 paramLI = _SPI_convert_params(nargs, argtypes,
00508 Values, Nulls);
00509
00510 _SPI_prepare_oneshot_plan(src, &plan);
00511
00512 res = _SPI_execute_plan(&plan, paramLI,
00513 InvalidSnapshot, InvalidSnapshot,
00514 read_only, true, tcount);
00515
00516 _SPI_end_call(true);
00517 return res;
00518 }
00519
00520 SPIPlanPtr
00521 SPI_prepare(const char *src, int nargs, Oid *argtypes)
00522 {
00523 return SPI_prepare_cursor(src, nargs, argtypes, 0);
00524 }
00525
00526 SPIPlanPtr
00527 SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
00528 int cursorOptions)
00529 {
00530 _SPI_plan plan;
00531 SPIPlanPtr result;
00532
00533 if (src == NULL || nargs < 0 || (nargs > 0 && argtypes == NULL))
00534 {
00535 SPI_result = SPI_ERROR_ARGUMENT;
00536 return NULL;
00537 }
00538
00539 SPI_result = _SPI_begin_call(true);
00540 if (SPI_result < 0)
00541 return NULL;
00542
00543 memset(&plan, 0, sizeof(_SPI_plan));
00544 plan.magic = _SPI_PLAN_MAGIC;
00545 plan.cursor_options = cursorOptions;
00546 plan.nargs = nargs;
00547 plan.argtypes = argtypes;
00548 plan.parserSetup = NULL;
00549 plan.parserSetupArg = NULL;
00550
00551 _SPI_prepare_plan(src, &plan);
00552
00553
00554 result = _SPI_make_plan_non_temp(&plan);
00555
00556 _SPI_end_call(true);
00557
00558 return result;
00559 }
00560
00561 SPIPlanPtr
00562 SPI_prepare_params(const char *src,
00563 ParserSetupHook parserSetup,
00564 void *parserSetupArg,
00565 int cursorOptions)
00566 {
00567 _SPI_plan plan;
00568 SPIPlanPtr result;
00569
00570 if (src == NULL)
00571 {
00572 SPI_result = SPI_ERROR_ARGUMENT;
00573 return NULL;
00574 }
00575
00576 SPI_result = _SPI_begin_call(true);
00577 if (SPI_result < 0)
00578 return NULL;
00579
00580 memset(&plan, 0, sizeof(_SPI_plan));
00581 plan.magic = _SPI_PLAN_MAGIC;
00582 plan.cursor_options = cursorOptions;
00583 plan.nargs = 0;
00584 plan.argtypes = NULL;
00585 plan.parserSetup = parserSetup;
00586 plan.parserSetupArg = parserSetupArg;
00587
00588 _SPI_prepare_plan(src, &plan);
00589
00590
00591 result = _SPI_make_plan_non_temp(&plan);
00592
00593 _SPI_end_call(true);
00594
00595 return result;
00596 }
00597
00598 int
00599 SPI_keepplan(SPIPlanPtr plan)
00600 {
00601 ListCell *lc;
00602
00603 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
00604 plan->saved || plan->oneshot)
00605 return SPI_ERROR_ARGUMENT;
00606
00607
00608
00609
00610
00611
00612 plan->saved = true;
00613 MemoryContextSetParent(plan->plancxt, CacheMemoryContext);
00614
00615 foreach(lc, plan->plancache_list)
00616 {
00617 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
00618
00619 SaveCachedPlan(plansource);
00620 }
00621
00622 return 0;
00623 }
00624
00625 SPIPlanPtr
00626 SPI_saveplan(SPIPlanPtr plan)
00627 {
00628 SPIPlanPtr newplan;
00629
00630 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
00631 {
00632 SPI_result = SPI_ERROR_ARGUMENT;
00633 return NULL;
00634 }
00635
00636 SPI_result = _SPI_begin_call(false);
00637 if (SPI_result < 0)
00638 return NULL;
00639
00640 newplan = _SPI_save_plan(plan);
00641
00642 SPI_result = _SPI_end_call(false);
00643
00644 return newplan;
00645 }
00646
00647 int
00648 SPI_freeplan(SPIPlanPtr plan)
00649 {
00650 ListCell *lc;
00651
00652 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
00653 return SPI_ERROR_ARGUMENT;
00654
00655
00656 foreach(lc, plan->plancache_list)
00657 {
00658 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
00659
00660 DropCachedPlan(plansource);
00661 }
00662
00663
00664 MemoryContextDelete(plan->plancxt);
00665
00666 return 0;
00667 }
00668
00669 HeapTuple
00670 SPI_copytuple(HeapTuple tuple)
00671 {
00672 MemoryContext oldcxt = NULL;
00673 HeapTuple ctuple;
00674
00675 if (tuple == NULL)
00676 {
00677 SPI_result = SPI_ERROR_ARGUMENT;
00678 return NULL;
00679 }
00680
00681 if (_SPI_curid + 1 == _SPI_connected)
00682 {
00683 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
00684 elog(ERROR, "SPI stack corrupted");
00685 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
00686 }
00687
00688 ctuple = heap_copytuple(tuple);
00689
00690 if (oldcxt)
00691 MemoryContextSwitchTo(oldcxt);
00692
00693 return ctuple;
00694 }
00695
00696 HeapTupleHeader
00697 SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc)
00698 {
00699 MemoryContext oldcxt = NULL;
00700 HeapTupleHeader dtup;
00701
00702 if (tuple == NULL || tupdesc == NULL)
00703 {
00704 SPI_result = SPI_ERROR_ARGUMENT;
00705 return NULL;
00706 }
00707
00708
00709 if (tupdesc->tdtypeid == RECORDOID &&
00710 tupdesc->tdtypmod < 0)
00711 assign_record_type_typmod(tupdesc);
00712
00713 if (_SPI_curid + 1 == _SPI_connected)
00714 {
00715 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
00716 elog(ERROR, "SPI stack corrupted");
00717 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
00718 }
00719
00720 dtup = (HeapTupleHeader) palloc(tuple->t_len);
00721 memcpy((char *) dtup, (char *) tuple->t_data, tuple->t_len);
00722
00723 HeapTupleHeaderSetDatumLength(dtup, tuple->t_len);
00724 HeapTupleHeaderSetTypeId(dtup, tupdesc->tdtypeid);
00725 HeapTupleHeaderSetTypMod(dtup, tupdesc->tdtypmod);
00726
00727 if (oldcxt)
00728 MemoryContextSwitchTo(oldcxt);
00729
00730 return dtup;
00731 }
00732
00733 HeapTuple
00734 SPI_modifytuple(Relation rel, HeapTuple tuple, int natts, int *attnum,
00735 Datum *Values, const char *Nulls)
00736 {
00737 MemoryContext oldcxt = NULL;
00738 HeapTuple mtuple;
00739 int numberOfAttributes;
00740 Datum *v;
00741 bool *n;
00742 int i;
00743
00744 if (rel == NULL || tuple == NULL || natts < 0 || attnum == NULL || Values == NULL)
00745 {
00746 SPI_result = SPI_ERROR_ARGUMENT;
00747 return NULL;
00748 }
00749
00750 if (_SPI_curid + 1 == _SPI_connected)
00751 {
00752 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
00753 elog(ERROR, "SPI stack corrupted");
00754 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
00755 }
00756 SPI_result = 0;
00757 numberOfAttributes = rel->rd_att->natts;
00758 v = (Datum *) palloc(numberOfAttributes * sizeof(Datum));
00759 n = (bool *) palloc(numberOfAttributes * sizeof(bool));
00760
00761
00762 heap_deform_tuple(tuple, rel->rd_att, v, n);
00763
00764
00765 for (i = 0; i < natts; i++)
00766 {
00767 if (attnum[i] <= 0 || attnum[i] > numberOfAttributes)
00768 break;
00769 v[attnum[i] - 1] = Values[i];
00770 n[attnum[i] - 1] = (Nulls && Nulls[i] == 'n') ? true : false;
00771 }
00772
00773 if (i == natts)
00774 {
00775 mtuple = heap_form_tuple(rel->rd_att, v, n);
00776
00777
00778
00779
00780
00781 mtuple->t_data->t_ctid = tuple->t_data->t_ctid;
00782 mtuple->t_self = tuple->t_self;
00783 mtuple->t_tableOid = tuple->t_tableOid;
00784 if (rel->rd_att->tdhasoid)
00785 HeapTupleSetOid(mtuple, HeapTupleGetOid(tuple));
00786 }
00787 else
00788 {
00789 mtuple = NULL;
00790 SPI_result = SPI_ERROR_NOATTRIBUTE;
00791 }
00792
00793 pfree(v);
00794 pfree(n);
00795
00796 if (oldcxt)
00797 MemoryContextSwitchTo(oldcxt);
00798
00799 return mtuple;
00800 }
00801
00802 int
00803 SPI_fnumber(TupleDesc tupdesc, const char *fname)
00804 {
00805 int res;
00806 Form_pg_attribute sysatt;
00807
00808 for (res = 0; res < tupdesc->natts; res++)
00809 {
00810 if (namestrcmp(&tupdesc->attrs[res]->attname, fname) == 0)
00811 return res + 1;
00812 }
00813
00814 sysatt = SystemAttributeByName(fname, true );
00815 if (sysatt != NULL)
00816 return sysatt->attnum;
00817
00818
00819 return SPI_ERROR_NOATTRIBUTE;
00820 }
00821
00822 char *
00823 SPI_fname(TupleDesc tupdesc, int fnumber)
00824 {
00825 Form_pg_attribute att;
00826
00827 SPI_result = 0;
00828
00829 if (fnumber > tupdesc->natts || fnumber == 0 ||
00830 fnumber <= FirstLowInvalidHeapAttributeNumber)
00831 {
00832 SPI_result = SPI_ERROR_NOATTRIBUTE;
00833 return NULL;
00834 }
00835
00836 if (fnumber > 0)
00837 att = tupdesc->attrs[fnumber - 1];
00838 else
00839 att = SystemAttributeDefinition(fnumber, true);
00840
00841 return pstrdup(NameStr(att->attname));
00842 }
00843
00844 char *
00845 SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber)
00846 {
00847 char *result;
00848 Datum origval,
00849 val;
00850 bool isnull;
00851 Oid typoid,
00852 foutoid;
00853 bool typisvarlena;
00854
00855 SPI_result = 0;
00856
00857 if (fnumber > tupdesc->natts || fnumber == 0 ||
00858 fnumber <= FirstLowInvalidHeapAttributeNumber)
00859 {
00860 SPI_result = SPI_ERROR_NOATTRIBUTE;
00861 return NULL;
00862 }
00863
00864 origval = heap_getattr(tuple, fnumber, tupdesc, &isnull);
00865 if (isnull)
00866 return NULL;
00867
00868 if (fnumber > 0)
00869 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
00870 else
00871 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
00872
00873 getTypeOutputInfo(typoid, &foutoid, &typisvarlena);
00874
00875
00876
00877
00878
00879 if (typisvarlena)
00880 val = PointerGetDatum(PG_DETOAST_DATUM(origval));
00881 else
00882 val = origval;
00883
00884 result = OidOutputFunctionCall(foutoid, val);
00885
00886
00887 if (val != origval)
00888 pfree(DatumGetPointer(val));
00889
00890 return result;
00891 }
00892
00893 Datum
00894 SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull)
00895 {
00896 SPI_result = 0;
00897
00898 if (fnumber > tupdesc->natts || fnumber == 0 ||
00899 fnumber <= FirstLowInvalidHeapAttributeNumber)
00900 {
00901 SPI_result = SPI_ERROR_NOATTRIBUTE;
00902 *isnull = true;
00903 return (Datum) NULL;
00904 }
00905
00906 return heap_getattr(tuple, fnumber, tupdesc, isnull);
00907 }
00908
00909 char *
00910 SPI_gettype(TupleDesc tupdesc, int fnumber)
00911 {
00912 Oid typoid;
00913 HeapTuple typeTuple;
00914 char *result;
00915
00916 SPI_result = 0;
00917
00918 if (fnumber > tupdesc->natts || fnumber == 0 ||
00919 fnumber <= FirstLowInvalidHeapAttributeNumber)
00920 {
00921 SPI_result = SPI_ERROR_NOATTRIBUTE;
00922 return NULL;
00923 }
00924
00925 if (fnumber > 0)
00926 typoid = tupdesc->attrs[fnumber - 1]->atttypid;
00927 else
00928 typoid = (SystemAttributeDefinition(fnumber, true))->atttypid;
00929
00930 typeTuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typoid));
00931
00932 if (!HeapTupleIsValid(typeTuple))
00933 {
00934 SPI_result = SPI_ERROR_TYPUNKNOWN;
00935 return NULL;
00936 }
00937
00938 result = pstrdup(NameStr(((Form_pg_type) GETSTRUCT(typeTuple))->typname));
00939 ReleaseSysCache(typeTuple);
00940 return result;
00941 }
00942
00943 Oid
00944 SPI_gettypeid(TupleDesc tupdesc, int fnumber)
00945 {
00946 SPI_result = 0;
00947
00948 if (fnumber > tupdesc->natts || fnumber == 0 ||
00949 fnumber <= FirstLowInvalidHeapAttributeNumber)
00950 {
00951 SPI_result = SPI_ERROR_NOATTRIBUTE;
00952 return InvalidOid;
00953 }
00954
00955 if (fnumber > 0)
00956 return tupdesc->attrs[fnumber - 1]->atttypid;
00957 else
00958 return (SystemAttributeDefinition(fnumber, true))->atttypid;
00959 }
00960
00961 char *
00962 SPI_getrelname(Relation rel)
00963 {
00964 return pstrdup(RelationGetRelationName(rel));
00965 }
00966
00967 char *
00968 SPI_getnspname(Relation rel)
00969 {
00970 return get_namespace_name(RelationGetNamespace(rel));
00971 }
00972
00973 void *
00974 SPI_palloc(Size size)
00975 {
00976 MemoryContext oldcxt = NULL;
00977 void *pointer;
00978
00979 if (_SPI_curid + 1 == _SPI_connected)
00980 {
00981 if (_SPI_current != &(_SPI_stack[_SPI_curid + 1]))
00982 elog(ERROR, "SPI stack corrupted");
00983 oldcxt = MemoryContextSwitchTo(_SPI_current->savedcxt);
00984 }
00985
00986 pointer = palloc(size);
00987
00988 if (oldcxt)
00989 MemoryContextSwitchTo(oldcxt);
00990
00991 return pointer;
00992 }
00993
00994 void *
00995 SPI_repalloc(void *pointer, Size size)
00996 {
00997
00998 return repalloc(pointer, size);
00999 }
01000
01001 void
01002 SPI_pfree(void *pointer)
01003 {
01004
01005 pfree(pointer);
01006 }
01007
01008 void
01009 SPI_freetuple(HeapTuple tuple)
01010 {
01011
01012 heap_freetuple(tuple);
01013 }
01014
01015 void
01016 SPI_freetuptable(SPITupleTable *tuptable)
01017 {
01018 if (tuptable != NULL)
01019 MemoryContextDelete(tuptable->tuptabcxt);
01020 }
01021
01022
01023
01024
01025
01026
01027
01028 Portal
01029 SPI_cursor_open(const char *name, SPIPlanPtr plan,
01030 Datum *Values, const char *Nulls,
01031 bool read_only)
01032 {
01033 Portal portal;
01034 ParamListInfo paramLI;
01035
01036
01037 paramLI = _SPI_convert_params(plan->nargs, plan->argtypes,
01038 Values, Nulls);
01039
01040 portal = SPI_cursor_open_internal(name, plan, paramLI, read_only);
01041
01042
01043 if (paramLI)
01044 pfree(paramLI);
01045
01046 return portal;
01047 }
01048
01049
01050
01051
01052
01053
01054
01055 Portal
01056 SPI_cursor_open_with_args(const char *name,
01057 const char *src,
01058 int nargs, Oid *argtypes,
01059 Datum *Values, const char *Nulls,
01060 bool read_only, int cursorOptions)
01061 {
01062 Portal result;
01063 _SPI_plan plan;
01064 ParamListInfo paramLI;
01065
01066 if (src == NULL || nargs < 0)
01067 elog(ERROR, "SPI_cursor_open_with_args called with invalid arguments");
01068
01069 if (nargs > 0 && (argtypes == NULL || Values == NULL))
01070 elog(ERROR, "SPI_cursor_open_with_args called with missing parameters");
01071
01072 SPI_result = _SPI_begin_call(true);
01073 if (SPI_result < 0)
01074 elog(ERROR, "SPI_cursor_open_with_args called while not connected");
01075
01076 memset(&plan, 0, sizeof(_SPI_plan));
01077 plan.magic = _SPI_PLAN_MAGIC;
01078 plan.cursor_options = cursorOptions;
01079 plan.nargs = nargs;
01080 plan.argtypes = argtypes;
01081 plan.parserSetup = NULL;
01082 plan.parserSetupArg = NULL;
01083
01084
01085 paramLI = _SPI_convert_params(nargs, argtypes,
01086 Values, Nulls);
01087
01088 _SPI_prepare_plan(src, &plan);
01089
01090
01091
01092
01093 _SPI_curid--;
01094
01095 result = SPI_cursor_open_internal(name, &plan, paramLI, read_only);
01096
01097
01098 _SPI_curid++;
01099 _SPI_end_call(true);
01100
01101 return result;
01102 }
01103
01104
01105
01106
01107
01108
01109
01110
01111 Portal
01112 SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan,
01113 ParamListInfo params, bool read_only)
01114 {
01115 return SPI_cursor_open_internal(name, plan, params, read_only);
01116 }
01117
01118
01119
01120
01121
01122
01123
01124 static Portal
01125 SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
01126 ParamListInfo paramLI, bool read_only)
01127 {
01128 CachedPlanSource *plansource;
01129 CachedPlan *cplan;
01130 List *stmt_list;
01131 char *query_string;
01132 Snapshot snapshot;
01133 MemoryContext oldcontext;
01134 Portal portal;
01135 ErrorContextCallback spierrcontext;
01136
01137
01138
01139
01140
01141 if (!SPI_is_cursor_plan(plan))
01142 {
01143
01144 if (list_length(plan->plancache_list) != 1)
01145 ereport(ERROR,
01146 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
01147 errmsg("cannot open multi-query plan as cursor")));
01148 plansource = (CachedPlanSource *) linitial(plan->plancache_list);
01149 ereport(ERROR,
01150 (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
01151
01152 errmsg("cannot open %s query as cursor",
01153 plansource->commandTag)));
01154 }
01155
01156 Assert(list_length(plan->plancache_list) == 1);
01157 plansource = (CachedPlanSource *) linitial(plan->plancache_list);
01158
01159
01160 if (_SPI_begin_call(true) < 0)
01161 elog(ERROR, "SPI_cursor_open called while not connected");
01162
01163
01164 SPI_processed = 0;
01165 SPI_tuptable = NULL;
01166 _SPI_current->processed = 0;
01167 _SPI_current->tuptable = NULL;
01168
01169
01170 if (name == NULL || name[0] == '\0')
01171 {
01172
01173 portal = CreateNewPortal();
01174 }
01175 else
01176 {
01177
01178 portal = CreatePortal(name, false, false);
01179 }
01180
01181
01182 query_string = MemoryContextStrdup(PortalGetHeapMemory(portal),
01183 plansource->query_string);
01184
01185
01186
01187
01188
01189 spierrcontext.callback = _SPI_error_callback;
01190 spierrcontext.arg = (void *) plansource->query_string;
01191 spierrcontext.previous = error_context_stack;
01192 error_context_stack = &spierrcontext;
01193
01194
01195
01196
01197
01198
01199
01200
01201 cplan = GetCachedPlan(plansource, paramLI, false);
01202 stmt_list = cplan->stmt_list;
01203
01204
01205 error_context_stack = spierrcontext.previous;
01206
01207 if (!plan->saved)
01208 {
01209
01210
01211
01212
01213
01214
01215 oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
01216 stmt_list = copyObject(stmt_list);
01217 MemoryContextSwitchTo(oldcontext);
01218 ReleaseCachedPlan(cplan, false);
01219 cplan = NULL;
01220 }
01221
01222
01223
01224
01225 PortalDefineQuery(portal,
01226 NULL,
01227 query_string,
01228 plansource->commandTag,
01229 stmt_list,
01230 cplan);
01231
01232
01233
01234
01235
01236 portal->cursorOptions = plan->cursor_options;
01237 if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
01238 {
01239 if (list_length(stmt_list) == 1 &&
01240 IsA((Node *) linitial(stmt_list), PlannedStmt) &&
01241 ((PlannedStmt *) linitial(stmt_list))->rowMarks == NIL &&
01242 ExecSupportsBackwardScan(((PlannedStmt *) linitial(stmt_list))->planTree))
01243 portal->cursorOptions |= CURSOR_OPT_SCROLL;
01244 else
01245 portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
01246 }
01247
01248
01249
01250
01251
01252
01253 if (portal->cursorOptions & CURSOR_OPT_SCROLL)
01254 {
01255 if (list_length(stmt_list) == 1 &&
01256 IsA((Node *) linitial(stmt_list), PlannedStmt) &&
01257 ((PlannedStmt *) linitial(stmt_list))->rowMarks != NIL)
01258 ereport(ERROR,
01259 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01260 errmsg("DECLARE SCROLL CURSOR ... FOR UPDATE/SHARE is not supported"),
01261 errdetail("Scrollable cursors must be READ ONLY.")));
01262 }
01263
01264
01265
01266
01267
01268
01269
01270
01271 if (read_only)
01272 {
01273 ListCell *lc;
01274
01275 foreach(lc, stmt_list)
01276 {
01277 Node *pstmt = (Node *) lfirst(lc);
01278
01279 if (!CommandIsReadOnly(pstmt))
01280 ereport(ERROR,
01281 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
01282
01283 errmsg("%s is not allowed in a non-volatile function",
01284 CreateCommandTag(pstmt))));
01285 }
01286 }
01287
01288
01289 if (read_only)
01290 snapshot = GetActiveSnapshot();
01291 else
01292 {
01293 CommandCounterIncrement();
01294 snapshot = GetTransactionSnapshot();
01295 }
01296
01297
01298
01299
01300
01301
01302 if (paramLI)
01303 {
01304 oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
01305 paramLI = copyParamList(paramLI);
01306 MemoryContextSwitchTo(oldcontext);
01307 }
01308
01309
01310
01311
01312 PortalStart(portal, paramLI, 0, snapshot);
01313
01314 Assert(portal->strategy != PORTAL_MULTI_QUERY);
01315
01316
01317 _SPI_end_call(true);
01318
01319
01320 return portal;
01321 }
01322
01323
01324
01325
01326
01327
01328
01329 Portal
01330 SPI_cursor_find(const char *name)
01331 {
01332 return GetPortalByName(name);
01333 }
01334
01335
01336
01337
01338
01339
01340
01341 void
01342 SPI_cursor_fetch(Portal portal, bool forward, long count)
01343 {
01344 _SPI_cursor_operation(portal,
01345 forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
01346 CreateDestReceiver(DestSPI));
01347
01348 }
01349
01350
01351
01352
01353
01354
01355
01356 void
01357 SPI_cursor_move(Portal portal, bool forward, long count)
01358 {
01359 _SPI_cursor_operation(portal,
01360 forward ? FETCH_FORWARD : FETCH_BACKWARD, count,
01361 None_Receiver);
01362 }
01363
01364
01365
01366
01367
01368
01369
01370 void
01371 SPI_scroll_cursor_fetch(Portal portal, FetchDirection direction, long count)
01372 {
01373 _SPI_cursor_operation(portal,
01374 direction, count,
01375 CreateDestReceiver(DestSPI));
01376
01377 }
01378
01379
01380
01381
01382
01383
01384
01385 void
01386 SPI_scroll_cursor_move(Portal portal, FetchDirection direction, long count)
01387 {
01388 _SPI_cursor_operation(portal, direction, count, None_Receiver);
01389 }
01390
01391
01392
01393
01394
01395
01396
01397 void
01398 SPI_cursor_close(Portal portal)
01399 {
01400 if (!PortalIsValid(portal))
01401 elog(ERROR, "invalid portal in SPI cursor operation");
01402
01403 PortalDrop(portal, false);
01404 }
01405
01406
01407
01408
01409
01410 Oid
01411 SPI_getargtypeid(SPIPlanPtr plan, int argIndex)
01412 {
01413 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC ||
01414 argIndex < 0 || argIndex >= plan->nargs)
01415 {
01416 SPI_result = SPI_ERROR_ARGUMENT;
01417 return InvalidOid;
01418 }
01419 return plan->argtypes[argIndex];
01420 }
01421
01422
01423
01424
01425 int
01426 SPI_getargcount(SPIPlanPtr plan)
01427 {
01428 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
01429 {
01430 SPI_result = SPI_ERROR_ARGUMENT;
01431 return -1;
01432 }
01433 return plan->nargs;
01434 }
01435
01436
01437
01438
01439
01440
01441
01442
01443
01444
01445 bool
01446 SPI_is_cursor_plan(SPIPlanPtr plan)
01447 {
01448 CachedPlanSource *plansource;
01449
01450 if (plan == NULL || plan->magic != _SPI_PLAN_MAGIC)
01451 {
01452 SPI_result = SPI_ERROR_ARGUMENT;
01453 return false;
01454 }
01455
01456 if (list_length(plan->plancache_list) != 1)
01457 {
01458 SPI_result = 0;
01459 return false;
01460 }
01461 plansource = (CachedPlanSource *) linitial(plan->plancache_list);
01462
01463
01464
01465
01466
01467
01468 SPI_result = 0;
01469
01470
01471 if (plansource->resultDesc)
01472 return true;
01473
01474 return false;
01475 }
01476
01477
01478
01479
01480
01481
01482
01483 bool
01484 SPI_plan_is_valid(SPIPlanPtr plan)
01485 {
01486 ListCell *lc;
01487
01488 Assert(plan->magic == _SPI_PLAN_MAGIC);
01489
01490 foreach(lc, plan->plancache_list)
01491 {
01492 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
01493
01494 if (!CachedPlanIsValid(plansource))
01495 return false;
01496 }
01497 return true;
01498 }
01499
01500
01501
01502
01503
01504
01505
01506
01507 const char *
01508 SPI_result_code_string(int code)
01509 {
01510 static char buf[64];
01511
01512 switch (code)
01513 {
01514 case SPI_ERROR_CONNECT:
01515 return "SPI_ERROR_CONNECT";
01516 case SPI_ERROR_COPY:
01517 return "SPI_ERROR_COPY";
01518 case SPI_ERROR_OPUNKNOWN:
01519 return "SPI_ERROR_OPUNKNOWN";
01520 case SPI_ERROR_UNCONNECTED:
01521 return "SPI_ERROR_UNCONNECTED";
01522 case SPI_ERROR_ARGUMENT:
01523 return "SPI_ERROR_ARGUMENT";
01524 case SPI_ERROR_PARAM:
01525 return "SPI_ERROR_PARAM";
01526 case SPI_ERROR_TRANSACTION:
01527 return "SPI_ERROR_TRANSACTION";
01528 case SPI_ERROR_NOATTRIBUTE:
01529 return "SPI_ERROR_NOATTRIBUTE";
01530 case SPI_ERROR_NOOUTFUNC:
01531 return "SPI_ERROR_NOOUTFUNC";
01532 case SPI_ERROR_TYPUNKNOWN:
01533 return "SPI_ERROR_TYPUNKNOWN";
01534 case SPI_OK_CONNECT:
01535 return "SPI_OK_CONNECT";
01536 case SPI_OK_FINISH:
01537 return "SPI_OK_FINISH";
01538 case SPI_OK_FETCH:
01539 return "SPI_OK_FETCH";
01540 case SPI_OK_UTILITY:
01541 return "SPI_OK_UTILITY";
01542 case SPI_OK_SELECT:
01543 return "SPI_OK_SELECT";
01544 case SPI_OK_SELINTO:
01545 return "SPI_OK_SELINTO";
01546 case SPI_OK_INSERT:
01547 return "SPI_OK_INSERT";
01548 case SPI_OK_DELETE:
01549 return "SPI_OK_DELETE";
01550 case SPI_OK_UPDATE:
01551 return "SPI_OK_UPDATE";
01552 case SPI_OK_CURSOR:
01553 return "SPI_OK_CURSOR";
01554 case SPI_OK_INSERT_RETURNING:
01555 return "SPI_OK_INSERT_RETURNING";
01556 case SPI_OK_DELETE_RETURNING:
01557 return "SPI_OK_DELETE_RETURNING";
01558 case SPI_OK_UPDATE_RETURNING:
01559 return "SPI_OK_UPDATE_RETURNING";
01560 case SPI_OK_REWRITTEN:
01561 return "SPI_OK_REWRITTEN";
01562 }
01563
01564 sprintf(buf, "Unrecognized SPI code %d", code);
01565 return buf;
01566 }
01567
01568
01569
01570
01571
01572
01573
01574
01575
01576 List *
01577 SPI_plan_get_plan_sources(SPIPlanPtr plan)
01578 {
01579 Assert(plan->magic == _SPI_PLAN_MAGIC);
01580 return plan->plancache_list;
01581 }
01582
01583
01584
01585
01586
01587
01588
01589
01590
01591
01592 CachedPlan *
01593 SPI_plan_get_cached_plan(SPIPlanPtr plan)
01594 {
01595 CachedPlanSource *plansource;
01596 CachedPlan *cplan;
01597 ErrorContextCallback spierrcontext;
01598
01599 Assert(plan->magic == _SPI_PLAN_MAGIC);
01600
01601
01602 if (plan->oneshot)
01603 return NULL;
01604
01605
01606 if (list_length(plan->plancache_list) != 1)
01607 return NULL;
01608 plansource = (CachedPlanSource *) linitial(plan->plancache_list);
01609
01610
01611 spierrcontext.callback = _SPI_error_callback;
01612 spierrcontext.arg = (void *) plansource->query_string;
01613 spierrcontext.previous = error_context_stack;
01614 error_context_stack = &spierrcontext;
01615
01616
01617 cplan = GetCachedPlan(plansource, NULL, plan->saved);
01618 Assert(cplan == plansource->gplan);
01619
01620
01621 error_context_stack = spierrcontext.previous;
01622
01623 return cplan;
01624 }
01625
01626
01627
01628
01629
01630
01631
01632
01633
01634 void
01635 spi_dest_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
01636 {
01637 SPITupleTable *tuptable;
01638 MemoryContext oldcxt;
01639 MemoryContext tuptabcxt;
01640
01641
01642
01643
01644
01645 if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
01646 elog(ERROR, "improper call to spi_dest_startup");
01647 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
01648 elog(ERROR, "SPI stack corrupted");
01649
01650 if (_SPI_current->tuptable != NULL)
01651 elog(ERROR, "improper call to spi_dest_startup");
01652
01653 oldcxt = _SPI_procmem();
01654
01655 tuptabcxt = AllocSetContextCreate(CurrentMemoryContext,
01656 "SPI TupTable",
01657 ALLOCSET_DEFAULT_MINSIZE,
01658 ALLOCSET_DEFAULT_INITSIZE,
01659 ALLOCSET_DEFAULT_MAXSIZE);
01660 MemoryContextSwitchTo(tuptabcxt);
01661
01662 _SPI_current->tuptable = tuptable = (SPITupleTable *)
01663 palloc(sizeof(SPITupleTable));
01664 tuptable->tuptabcxt = tuptabcxt;
01665 tuptable->alloced = tuptable->free = 128;
01666 tuptable->vals = (HeapTuple *) palloc(tuptable->alloced * sizeof(HeapTuple));
01667 tuptable->tupdesc = CreateTupleDescCopy(typeinfo);
01668
01669 MemoryContextSwitchTo(oldcxt);
01670 }
01671
01672
01673
01674
01675
01676
01677 void
01678 spi_printtup(TupleTableSlot *slot, DestReceiver *self)
01679 {
01680 SPITupleTable *tuptable;
01681 MemoryContext oldcxt;
01682
01683
01684
01685
01686
01687 if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
01688 elog(ERROR, "improper call to spi_printtup");
01689 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
01690 elog(ERROR, "SPI stack corrupted");
01691
01692 tuptable = _SPI_current->tuptable;
01693 if (tuptable == NULL)
01694 elog(ERROR, "improper call to spi_printtup");
01695
01696 oldcxt = MemoryContextSwitchTo(tuptable->tuptabcxt);
01697
01698 if (tuptable->free == 0)
01699 {
01700 tuptable->free = 256;
01701 tuptable->alloced += tuptable->free;
01702 tuptable->vals = (HeapTuple *) repalloc(tuptable->vals,
01703 tuptable->alloced * sizeof(HeapTuple));
01704 }
01705
01706 tuptable->vals[tuptable->alloced - tuptable->free] =
01707 ExecCopySlotTuple(slot);
01708 (tuptable->free)--;
01709
01710 MemoryContextSwitchTo(oldcxt);
01711 }
01712
01713
01714
01715
01716
01717
01718
01719
01720
01721
01722
01723
01724
01725
01726
01727
01728
01729 static void
01730 _SPI_prepare_plan(const char *src, SPIPlanPtr plan)
01731 {
01732 List *raw_parsetree_list;
01733 List *plancache_list;
01734 ListCell *list_item;
01735 ErrorContextCallback spierrcontext;
01736
01737
01738
01739
01740 spierrcontext.callback = _SPI_error_callback;
01741 spierrcontext.arg = (void *) src;
01742 spierrcontext.previous = error_context_stack;
01743 error_context_stack = &spierrcontext;
01744
01745
01746
01747
01748 raw_parsetree_list = pg_parse_query(src);
01749
01750
01751
01752
01753
01754 plancache_list = NIL;
01755
01756 foreach(list_item, raw_parsetree_list)
01757 {
01758 Node *parsetree = (Node *) lfirst(list_item);
01759 List *stmt_list;
01760 CachedPlanSource *plansource;
01761
01762
01763
01764
01765
01766 plansource = CreateCachedPlan(parsetree,
01767 src,
01768 CreateCommandTag(parsetree));
01769
01770
01771
01772
01773
01774 if (plan->parserSetup != NULL)
01775 {
01776 Assert(plan->nargs == 0);
01777 stmt_list = pg_analyze_and_rewrite_params(parsetree,
01778 src,
01779 plan->parserSetup,
01780 plan->parserSetupArg);
01781 }
01782 else
01783 {
01784 stmt_list = pg_analyze_and_rewrite(parsetree,
01785 src,
01786 plan->argtypes,
01787 plan->nargs);
01788 }
01789
01790
01791 CompleteCachedPlan(plansource,
01792 stmt_list,
01793 NULL,
01794 plan->argtypes,
01795 plan->nargs,
01796 plan->parserSetup,
01797 plan->parserSetupArg,
01798 plan->cursor_options,
01799 false);
01800
01801 plancache_list = lappend(plancache_list, plansource);
01802 }
01803
01804 plan->plancache_list = plancache_list;
01805 plan->oneshot = false;
01806
01807
01808
01809
01810 error_context_stack = spierrcontext.previous;
01811 }
01812
01813
01814
01815
01816
01817
01818
01819
01820
01821
01822
01823
01824
01825
01826
01827
01828
01829
01830
01831
01832 static void
01833 _SPI_prepare_oneshot_plan(const char *src, SPIPlanPtr plan)
01834 {
01835 List *raw_parsetree_list;
01836 List *plancache_list;
01837 ListCell *list_item;
01838 ErrorContextCallback spierrcontext;
01839
01840
01841
01842
01843 spierrcontext.callback = _SPI_error_callback;
01844 spierrcontext.arg = (void *) src;
01845 spierrcontext.previous = error_context_stack;
01846 error_context_stack = &spierrcontext;
01847
01848
01849
01850
01851 raw_parsetree_list = pg_parse_query(src);
01852
01853
01854
01855
01856 plancache_list = NIL;
01857
01858 foreach(list_item, raw_parsetree_list)
01859 {
01860 Node *parsetree = (Node *) lfirst(list_item);
01861 CachedPlanSource *plansource;
01862
01863 plansource = CreateOneShotCachedPlan(parsetree,
01864 src,
01865 CreateCommandTag(parsetree));
01866
01867 plancache_list = lappend(plancache_list, plansource);
01868 }
01869
01870 plan->plancache_list = plancache_list;
01871 plan->oneshot = true;
01872
01873
01874
01875
01876 error_context_stack = spierrcontext.previous;
01877 }
01878
01879
01880
01881
01882
01883
01884
01885
01886
01887
01888
01889
01890 static int
01891 _SPI_execute_plan(SPIPlanPtr plan, ParamListInfo paramLI,
01892 Snapshot snapshot, Snapshot crosscheck_snapshot,
01893 bool read_only, bool fire_triggers, long tcount)
01894 {
01895 int my_res = 0;
01896 uint32 my_processed = 0;
01897 Oid my_lastoid = InvalidOid;
01898 SPITupleTable *my_tuptable = NULL;
01899 int res = 0;
01900 bool pushed_active_snap = false;
01901 ErrorContextCallback spierrcontext;
01902 CachedPlan *cplan = NULL;
01903 ListCell *lc1;
01904
01905
01906
01907
01908 spierrcontext.callback = _SPI_error_callback;
01909 spierrcontext.arg = NULL;
01910 spierrcontext.previous = error_context_stack;
01911 error_context_stack = &spierrcontext;
01912
01913
01914
01915
01916
01917
01918
01919
01920
01921
01922
01923
01924
01925
01926
01927
01928
01929
01930
01931
01932 if (snapshot != InvalidSnapshot)
01933 {
01934 if (read_only)
01935 {
01936 PushActiveSnapshot(snapshot);
01937 pushed_active_snap = true;
01938 }
01939 else
01940 {
01941
01942 PushCopiedSnapshot(snapshot);
01943 pushed_active_snap = true;
01944 }
01945 }
01946
01947 foreach(lc1, plan->plancache_list)
01948 {
01949 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc1);
01950 List *stmt_list;
01951 ListCell *lc2;
01952
01953 spierrcontext.arg = (void *) plansource->query_string;
01954
01955
01956
01957
01958 if (plan->oneshot)
01959 {
01960 Node *parsetree = plansource->raw_parse_tree;
01961 const char *src = plansource->query_string;
01962 List *stmt_list;
01963
01964
01965
01966
01967
01968 if (plan->parserSetup != NULL)
01969 {
01970 Assert(plan->nargs == 0);
01971 stmt_list = pg_analyze_and_rewrite_params(parsetree,
01972 src,
01973 plan->parserSetup,
01974 plan->parserSetupArg);
01975 }
01976 else
01977 {
01978 stmt_list = pg_analyze_and_rewrite(parsetree,
01979 src,
01980 plan->argtypes,
01981 plan->nargs);
01982 }
01983
01984
01985 CompleteCachedPlan(plansource,
01986 stmt_list,
01987 NULL,
01988 plan->argtypes,
01989 plan->nargs,
01990 plan->parserSetup,
01991 plan->parserSetupArg,
01992 plan->cursor_options,
01993 false);
01994 }
01995
01996
01997
01998
01999
02000 cplan = GetCachedPlan(plansource, paramLI, plan->saved);
02001 stmt_list = cplan->stmt_list;
02002
02003
02004
02005
02006
02007 if (snapshot == InvalidSnapshot && !read_only)
02008 {
02009 if (pushed_active_snap)
02010 PopActiveSnapshot();
02011 PushActiveSnapshot(GetTransactionSnapshot());
02012 pushed_active_snap = true;
02013 }
02014
02015 foreach(lc2, stmt_list)
02016 {
02017 Node *stmt = (Node *) lfirst(lc2);
02018 bool canSetTag;
02019 DestReceiver *dest;
02020
02021 _SPI_current->processed = 0;
02022 _SPI_current->lastoid = InvalidOid;
02023 _SPI_current->tuptable = NULL;
02024
02025 if (IsA(stmt, PlannedStmt))
02026 {
02027 canSetTag = ((PlannedStmt *) stmt)->canSetTag;
02028 }
02029 else
02030 {
02031
02032 canSetTag = (list_length(stmt_list) == 1);
02033
02034 if (IsA(stmt, CopyStmt))
02035 {
02036 CopyStmt *cstmt = (CopyStmt *) stmt;
02037
02038 if (cstmt->filename == NULL)
02039 {
02040 my_res = SPI_ERROR_COPY;
02041 goto fail;
02042 }
02043 }
02044 else if (IsA(stmt, TransactionStmt))
02045 {
02046 my_res = SPI_ERROR_TRANSACTION;
02047 goto fail;
02048 }
02049 }
02050
02051 if (read_only && !CommandIsReadOnly(stmt))
02052 ereport(ERROR,
02053 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
02054
02055 errmsg("%s is not allowed in a non-volatile function",
02056 CreateCommandTag(stmt))));
02057
02058
02059
02060
02061
02062 if (!read_only)
02063 {
02064 CommandCounterIncrement();
02065 UpdateActiveSnapshotCommandId();
02066 }
02067
02068 dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone);
02069
02070 if (IsA(stmt, PlannedStmt) &&
02071 ((PlannedStmt *) stmt)->utilityStmt == NULL)
02072 {
02073 QueryDesc *qdesc;
02074 Snapshot snap;
02075
02076 if (ActiveSnapshotSet())
02077 snap = GetActiveSnapshot();
02078 else
02079 snap = InvalidSnapshot;
02080
02081 qdesc = CreateQueryDesc((PlannedStmt *) stmt,
02082 plansource->query_string,
02083 snap, crosscheck_snapshot,
02084 dest,
02085 paramLI, 0);
02086 res = _SPI_pquery(qdesc, fire_triggers,
02087 canSetTag ? tcount : 0);
02088 FreeQueryDesc(qdesc);
02089 }
02090 else
02091 {
02092 char completionTag[COMPLETION_TAG_BUFSIZE];
02093
02094 ProcessUtility(stmt,
02095 plansource->query_string,
02096 PROCESS_UTILITY_QUERY,
02097 paramLI,
02098 dest,
02099 completionTag);
02100
02101
02102 if (_SPI_current->tuptable)
02103 _SPI_current->processed = _SPI_current->tuptable->alloced -
02104 _SPI_current->tuptable->free;
02105
02106 res = SPI_OK_UTILITY;
02107
02108
02109
02110
02111
02112 if (IsA(stmt, CreateTableAsStmt))
02113 {
02114 Assert(strncmp(completionTag, "SELECT ", 7) == 0);
02115 _SPI_current->processed = strtoul(completionTag + 7,
02116 NULL, 10);
02117
02118
02119
02120
02121
02122 if (((CreateTableAsStmt *) stmt)->is_select_into)
02123 res = SPI_OK_SELINTO;
02124 }
02125 else if (IsA(stmt, CopyStmt))
02126 {
02127 Assert(strncmp(completionTag, "COPY ", 5) == 0);
02128 _SPI_current->processed = strtoul(completionTag + 5,
02129 NULL, 10);
02130 }
02131 }
02132
02133
02134
02135
02136
02137
02138 if (canSetTag)
02139 {
02140 my_processed = _SPI_current->processed;
02141 my_lastoid = _SPI_current->lastoid;
02142 SPI_freetuptable(my_tuptable);
02143 my_tuptable = _SPI_current->tuptable;
02144 my_res = res;
02145 }
02146 else
02147 {
02148 SPI_freetuptable(_SPI_current->tuptable);
02149 _SPI_current->tuptable = NULL;
02150 }
02151
02152 if (res < 0)
02153 {
02154 my_res = res;
02155 goto fail;
02156 }
02157 }
02158
02159
02160 ReleaseCachedPlan(cplan, plan->saved);
02161 cplan = NULL;
02162
02163
02164
02165
02166
02167
02168 if (!read_only)
02169 CommandCounterIncrement();
02170 }
02171
02172 fail:
02173
02174
02175 if (pushed_active_snap)
02176 PopActiveSnapshot();
02177
02178
02179 if (cplan)
02180 ReleaseCachedPlan(cplan, plan->saved);
02181
02182
02183
02184
02185 error_context_stack = spierrcontext.previous;
02186
02187
02188 SPI_processed = my_processed;
02189 SPI_lastoid = my_lastoid;
02190 SPI_tuptable = my_tuptable;
02191
02192
02193 _SPI_current->tuptable = NULL;
02194
02195
02196
02197
02198
02199
02200 if (my_res == 0)
02201 my_res = SPI_OK_REWRITTEN;
02202
02203 return my_res;
02204 }
02205
02206
02207
02208
02209 static ParamListInfo
02210 _SPI_convert_params(int nargs, Oid *argtypes,
02211 Datum *Values, const char *Nulls)
02212 {
02213 ParamListInfo paramLI;
02214
02215 if (nargs > 0)
02216 {
02217 int i;
02218
02219
02220 paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
02221 (nargs - 1) * sizeof(ParamExternData));
02222
02223 paramLI->paramFetch = NULL;
02224 paramLI->paramFetchArg = NULL;
02225 paramLI->parserSetup = NULL;
02226 paramLI->parserSetupArg = NULL;
02227 paramLI->numParams = nargs;
02228
02229 for (i = 0; i < nargs; i++)
02230 {
02231 ParamExternData *prm = ¶mLI->params[i];
02232
02233 prm->value = Values[i];
02234 prm->isnull = (Nulls && Nulls[i] == 'n');
02235 prm->pflags = PARAM_FLAG_CONST;
02236 prm->ptype = argtypes[i];
02237 }
02238 }
02239 else
02240 paramLI = NULL;
02241 return paramLI;
02242 }
02243
02244 static int
02245 _SPI_pquery(QueryDesc *queryDesc, bool fire_triggers, long tcount)
02246 {
02247 int operation = queryDesc->operation;
02248 int eflags;
02249 int res;
02250
02251 switch (operation)
02252 {
02253 case CMD_SELECT:
02254 Assert(queryDesc->plannedstmt->utilityStmt == NULL);
02255 if (queryDesc->dest->mydest != DestSPI)
02256 {
02257
02258 res = SPI_OK_UTILITY;
02259 }
02260 else
02261 res = SPI_OK_SELECT;
02262 break;
02263 case CMD_INSERT:
02264 if (queryDesc->plannedstmt->hasReturning)
02265 res = SPI_OK_INSERT_RETURNING;
02266 else
02267 res = SPI_OK_INSERT;
02268 break;
02269 case CMD_DELETE:
02270 if (queryDesc->plannedstmt->hasReturning)
02271 res = SPI_OK_DELETE_RETURNING;
02272 else
02273 res = SPI_OK_DELETE;
02274 break;
02275 case CMD_UPDATE:
02276 if (queryDesc->plannedstmt->hasReturning)
02277 res = SPI_OK_UPDATE_RETURNING;
02278 else
02279 res = SPI_OK_UPDATE;
02280 break;
02281 default:
02282 return SPI_ERROR_OPUNKNOWN;
02283 }
02284
02285 #ifdef SPI_EXECUTOR_STATS
02286 if (ShowExecutorStats)
02287 ResetUsage();
02288 #endif
02289
02290
02291 if (fire_triggers)
02292 eflags = 0;
02293 else
02294 eflags = EXEC_FLAG_SKIP_TRIGGERS;
02295
02296 ExecutorStart(queryDesc, eflags);
02297
02298 ExecutorRun(queryDesc, ForwardScanDirection, tcount);
02299
02300 _SPI_current->processed = queryDesc->estate->es_processed;
02301 _SPI_current->lastoid = queryDesc->estate->es_lastoid;
02302
02303 if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->hasReturning) &&
02304 queryDesc->dest->mydest == DestSPI)
02305 {
02306 if (_SPI_checktuples())
02307 elog(ERROR, "consistency check on SPI tuple count failed");
02308 }
02309
02310 ExecutorFinish(queryDesc);
02311 ExecutorEnd(queryDesc);
02312
02313
02314 #ifdef SPI_EXECUTOR_STATS
02315 if (ShowExecutorStats)
02316 ShowUsage("SPI EXECUTOR STATS");
02317 #endif
02318
02319 return res;
02320 }
02321
02322
02323
02324
02325
02326
02327 static void
02328 _SPI_error_callback(void *arg)
02329 {
02330 const char *query = (const char *) arg;
02331 int syntaxerrposition;
02332
02333
02334
02335
02336
02337 syntaxerrposition = geterrposition();
02338 if (syntaxerrposition > 0)
02339 {
02340 errposition(0);
02341 internalerrposition(syntaxerrposition);
02342 internalerrquery(query);
02343 }
02344 else
02345 errcontext("SQL statement \"%s\"", query);
02346 }
02347
02348
02349
02350
02351
02352
02353 static void
02354 _SPI_cursor_operation(Portal portal, FetchDirection direction, long count,
02355 DestReceiver *dest)
02356 {
02357 long nfetched;
02358
02359
02360 if (!PortalIsValid(portal))
02361 elog(ERROR, "invalid portal in SPI cursor operation");
02362
02363
02364 if (_SPI_begin_call(true) < 0)
02365 elog(ERROR, "SPI cursor operation called while not connected");
02366
02367
02368 SPI_processed = 0;
02369 SPI_tuptable = NULL;
02370 _SPI_current->processed = 0;
02371 _SPI_current->tuptable = NULL;
02372
02373
02374 nfetched = PortalRunFetch(portal,
02375 direction,
02376 count,
02377 dest);
02378
02379
02380
02381
02382
02383
02384
02385
02386
02387 _SPI_current->processed = nfetched;
02388
02389 if (dest->mydest == DestSPI && _SPI_checktuples())
02390 elog(ERROR, "consistency check on SPI tuple count failed");
02391
02392
02393 SPI_processed = _SPI_current->processed;
02394 SPI_tuptable = _SPI_current->tuptable;
02395
02396
02397 _SPI_current->tuptable = NULL;
02398
02399
02400 _SPI_end_call(true);
02401 }
02402
02403
02404 static MemoryContext
02405 _SPI_execmem(void)
02406 {
02407 return MemoryContextSwitchTo(_SPI_current->execCxt);
02408 }
02409
02410 static MemoryContext
02411 _SPI_procmem(void)
02412 {
02413 return MemoryContextSwitchTo(_SPI_current->procCxt);
02414 }
02415
02416
02417
02418
02419 static int
02420 _SPI_begin_call(bool execmem)
02421 {
02422 if (_SPI_curid + 1 != _SPI_connected)
02423 return SPI_ERROR_UNCONNECTED;
02424 _SPI_curid++;
02425 if (_SPI_current != &(_SPI_stack[_SPI_curid]))
02426 elog(ERROR, "SPI stack corrupted");
02427
02428 if (execmem)
02429 _SPI_execmem();
02430
02431 return 0;
02432 }
02433
02434
02435
02436
02437
02438
02439 static int
02440 _SPI_end_call(bool procmem)
02441 {
02442
02443
02444
02445 _SPI_curid--;
02446
02447 if (procmem)
02448 {
02449 _SPI_procmem();
02450
02451 MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
02452 }
02453
02454 return 0;
02455 }
02456
02457 static bool
02458 _SPI_checktuples(void)
02459 {
02460 uint32 processed = _SPI_current->processed;
02461 SPITupleTable *tuptable = _SPI_current->tuptable;
02462 bool failed = false;
02463
02464 if (tuptable == NULL)
02465 failed = true;
02466 else if (processed != (tuptable->alloced - tuptable->free))
02467 failed = true;
02468
02469 return failed;
02470 }
02471
02472
02473
02474
02475
02476
02477
02478
02479
02480
02481 static SPIPlanPtr
02482 _SPI_make_plan_non_temp(SPIPlanPtr plan)
02483 {
02484 SPIPlanPtr newplan;
02485 MemoryContext parentcxt = _SPI_current->procCxt;
02486 MemoryContext plancxt;
02487 MemoryContext oldcxt;
02488 ListCell *lc;
02489
02490
02491 Assert(plan->magic == _SPI_PLAN_MAGIC);
02492 Assert(plan->plancxt == NULL);
02493
02494 Assert(!plan->oneshot);
02495
02496
02497
02498
02499
02500
02501 plancxt = AllocSetContextCreate(parentcxt,
02502 "SPI Plan",
02503 ALLOCSET_SMALL_MINSIZE,
02504 ALLOCSET_SMALL_INITSIZE,
02505 ALLOCSET_SMALL_MAXSIZE);
02506 oldcxt = MemoryContextSwitchTo(plancxt);
02507
02508
02509 newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan));
02510 newplan->magic = _SPI_PLAN_MAGIC;
02511 newplan->saved = false;
02512 newplan->oneshot = false;
02513 newplan->plancache_list = NIL;
02514 newplan->plancxt = plancxt;
02515 newplan->cursor_options = plan->cursor_options;
02516 newplan->nargs = plan->nargs;
02517 if (plan->nargs > 0)
02518 {
02519 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
02520 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
02521 }
02522 else
02523 newplan->argtypes = NULL;
02524 newplan->parserSetup = plan->parserSetup;
02525 newplan->parserSetupArg = plan->parserSetupArg;
02526
02527
02528
02529
02530
02531
02532
02533 foreach(lc, plan->plancache_list)
02534 {
02535 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
02536
02537 CachedPlanSetParentContext(plansource, parentcxt);
02538
02539
02540 newplan->plancache_list = lappend(newplan->plancache_list, plansource);
02541 }
02542
02543 MemoryContextSwitchTo(oldcxt);
02544
02545
02546 plan->plancache_list = NIL;
02547
02548 return newplan;
02549 }
02550
02551
02552
02553
02554 static SPIPlanPtr
02555 _SPI_save_plan(SPIPlanPtr plan)
02556 {
02557 SPIPlanPtr newplan;
02558 MemoryContext plancxt;
02559 MemoryContext oldcxt;
02560 ListCell *lc;
02561
02562
02563 Assert(!plan->oneshot);
02564
02565
02566
02567
02568
02569
02570 plancxt = AllocSetContextCreate(CurrentMemoryContext,
02571 "SPI Plan",
02572 ALLOCSET_SMALL_MINSIZE,
02573 ALLOCSET_SMALL_INITSIZE,
02574 ALLOCSET_SMALL_MAXSIZE);
02575 oldcxt = MemoryContextSwitchTo(plancxt);
02576
02577
02578 newplan = (SPIPlanPtr) palloc(sizeof(_SPI_plan));
02579 newplan->magic = _SPI_PLAN_MAGIC;
02580 newplan->saved = false;
02581 newplan->oneshot = false;
02582 newplan->plancache_list = NIL;
02583 newplan->plancxt = plancxt;
02584 newplan->cursor_options = plan->cursor_options;
02585 newplan->nargs = plan->nargs;
02586 if (plan->nargs > 0)
02587 {
02588 newplan->argtypes = (Oid *) palloc(plan->nargs * sizeof(Oid));
02589 memcpy(newplan->argtypes, plan->argtypes, plan->nargs * sizeof(Oid));
02590 }
02591 else
02592 newplan->argtypes = NULL;
02593 newplan->parserSetup = plan->parserSetup;
02594 newplan->parserSetupArg = plan->parserSetupArg;
02595
02596
02597 foreach(lc, plan->plancache_list)
02598 {
02599 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
02600 CachedPlanSource *newsource;
02601
02602 newsource = CopyCachedPlan(plansource);
02603 newplan->plancache_list = lappend(newplan->plancache_list, newsource);
02604 }
02605
02606 MemoryContextSwitchTo(oldcxt);
02607
02608
02609
02610
02611
02612
02613 newplan->saved = true;
02614 MemoryContextSetParent(newplan->plancxt, CacheMemoryContext);
02615
02616 foreach(lc, newplan->plancache_list)
02617 {
02618 CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
02619
02620 SaveCachedPlan(plansource);
02621 }
02622
02623 return newplan;
02624 }