Header And Logo

PostgreSQL
| The world's most advanced open source database.

spi.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * spi.c
00004  *              Server Programming Interface
00005  *
00006  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00007  * Portions Copyright (c) 1994, Regents of the University of California
00008  *
00009  *
00010  * IDENTIFICATION
00011  *    src/backend/executor/spi.c
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;       /* allocated size of _SPI_stack */
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 /* =================== interface functions =================== */
00082 
00083 int
00084 SPI_connect(void)
00085 {
00086     int         newdepth;
00087 
00088     /*
00089      * When procedure called by Executor _SPI_curid expected to be equal to
00090      * _SPI_connected
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      * We're entering procedure where _SPI_curid == _SPI_connected - 1
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;       /* in case we fail to create 'em */
00130     _SPI_current->execCxt = NULL;
00131     _SPI_current->connectSubid = GetCurrentSubTransactionId();
00132 
00133     /*
00134      * Create memory contexts for this procedure
00135      *
00136      * XXX it would be better to use PortalContext as the parent context, but
00137      * we may not be inside a portal (consider deferred-trigger execution).
00138      * Perhaps CurTransactionContext would do?  For now it doesn't matter
00139      * because we clean up explicitly in AtEOSubXact_SPI().
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     /* ... and switch to procedure's context */
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);       /* live in procedure memory */
00163     if (res < 0)
00164         return res;
00165 
00166     /* Restore memory context as it was before procedure call */
00167     MemoryContextSwitchTo(_SPI_current->savedcxt);
00168 
00169     /* Release memory used in procedure call */
00170     MemoryContextDelete(_SPI_current->execCxt);
00171     _SPI_current->execCxt = NULL;
00172     MemoryContextDelete(_SPI_current->procCxt);
00173     _SPI_current->procCxt = NULL;
00174 
00175     /*
00176      * Reset result variables, especially SPI_tuptable which is probably
00177      * pointing at a just-deleted tuptable
00178      */
00179     SPI_processed = 0;
00180     SPI_lastoid = InvalidOid;
00181     SPI_tuptable = NULL;
00182 
00183     /*
00184      * After _SPI_begin_call _SPI_connected == _SPI_curid. Now we are closing
00185      * connection to SPI and returning to upper Executor and so _SPI_connected
00186      * must be equal to _SPI_curid.
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  * Clean up SPI state at transaction commit or abort.
00200  */
00201 void
00202 AtEOXact_SPI(bool isCommit)
00203 {
00204     /*
00205      * Note that memory contexts belonging to SPI stack entries will be freed
00206      * automatically, so we can ignore them here.  We just need to restore our
00207      * static variables to initial state.
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  * Clean up SPI state at subtransaction commit or abort.
00225  *
00226  * During commit, there shouldn't be any unclosed entries remaining from
00227  * the current subtransaction; we emit a warning if any are found.
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;              /* couldn't be any underneath it either */
00240 
00241         found = true;
00242 
00243         /*
00244          * Release procedure memory explicitly (see note in SPI_connect)
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          * Pop the stack entry and reset global variables.  Unlike
00259          * SPI_finish(), we don't risk switching to memory contexts that might
00260          * be already gone.
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      * If we are aborting a subtransaction and there is an open SPI context
00281      * surrounding the subxact, clean up to prevent memory leakage.
00282      */
00283     if (_SPI_current && !isCommit)
00284     {
00285         /* free Executor memory the same as _SPI_end_call would do */
00286         MemoryContextResetAndDeleteChildren(_SPI_current->execCxt);
00287         /* throw away any partially created tuple-table */
00288         SPI_freetuptable(_SPI_current->tuptable);
00289         _SPI_current->tuptable = NULL;
00290     }
00291 }
00292 
00293 
00294 /* Pushes SPI stack to allow recursive SPI calls */
00295 void
00296 SPI_push(void)
00297 {
00298     _SPI_curid++;
00299 }
00300 
00301 /* Pops SPI stack to allow recursive SPI calls */
00302 void
00303 SPI_pop(void)
00304 {
00305     _SPI_curid--;
00306 }
00307 
00308 /* Conditional push: push only if we're inside a SPI procedure */
00309 bool
00310 SPI_push_conditional(void)
00311 {
00312     bool        pushed = (_SPI_curid != _SPI_connected);
00313 
00314     if (pushed)
00315     {
00316         _SPI_curid++;
00317         /* We should now be in a state where SPI_connect would succeed */
00318         Assert(_SPI_curid == _SPI_connected);
00319     }
00320     return pushed;
00321 }
00322 
00323 /* Conditional pop: pop only if SPI_push_conditional pushed */
00324 void
00325 SPI_pop_conditional(bool pushed)
00326 {
00327     /* We should be in a state where SPI_connect would succeed */
00328     Assert(_SPI_curid == _SPI_connected);
00329     if (pushed)
00330         _SPI_curid--;
00331 }
00332 
00333 /* Restore state of SPI stack after aborting a subtransaction */
00334 void
00335 SPI_restore_connection(void)
00336 {
00337     Assert(_SPI_connected >= 0);
00338     _SPI_curid = _SPI_connected - 1;
00339 }
00340 
00341 /* Parse, plan, and execute a query string */
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 /* Obsolete version of SPI_execute */
00370 int
00371 SPI_exec(const char *src, long tcount)
00372 {
00373     return SPI_execute(src, false, tcount);
00374 }
00375 
00376 /* Execute a previously prepared plan */
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 /* Obsolete version of SPI_execute_plan */
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 /* Execute a previously prepared plan */
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  * SPI_execute_snapshot -- identical to SPI_execute_plan, except that we allow
00434  * the caller to specify exactly which snapshots to use, which will be
00435  * registered here.  Also, the caller may specify that AFTER triggers should be
00436  * queued as part of the outer query rather than being fired immediately at the
00437  * end of the command.
00438  *
00439  * This is currently not documented in spi.sgml because it is only intended
00440  * for use by RI triggers.
00441  *
00442  * Passing snapshot == InvalidSnapshot will select the normal behavior of
00443  * fetching a new snapshot for each query.
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  * SPI_execute_with_args -- plan and execute a query with supplied arguments
00475  *
00476  * This is functionally equivalent to SPI_prepare followed by
00477  * SPI_execute_plan.
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     /* copy plan to procedure context */
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     /* copy plan to procedure context */
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      * Mark it saved, reparent it under CacheMemoryContext, and mark all the
00609      * component CachedPlanSources as saved.  This sequence cannot fail
00610      * partway through, so there's no risk of long-term memory leakage.
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);        /* don't change context */
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     /* Release the plancache entries */
00656     foreach(lc, plan->plancache_list)
00657     {
00658         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
00659 
00660         DropCachedPlan(plansource);
00661     }
00662 
00663     /* Now get rid of the _SPI_plan and subsidiary data in its plancxt */
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)       /* 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     /* For RECORD results, make sure a typmod has been assigned */
00709     if (tupdesc->tdtypeid == RECORDOID &&
00710         tupdesc->tdtypmod < 0)
00711         assign_record_type_typmod(tupdesc);
00712 
00713     if (_SPI_curid + 1 == _SPI_connected)       /* 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)       /* 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     /* fetch old values and nulls */
00762     heap_deform_tuple(tuple, rel->rd_att, v, n);
00763 
00764     /* replace values and nulls */
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)             /* no errors in *attnum */
00774     {
00775         mtuple = heap_form_tuple(rel->rd_att, v, n);
00776 
00777         /*
00778          * copy the identification info of the old tuple: t_ctid, t_self, and
00779          * OID (if any)
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 /* "oid" will be accepted */ );
00815     if (sysatt != NULL)
00816         return sysatt->attnum;
00817 
00818     /* SPI_ERROR_NOATTRIBUTE is different from all sys column numbers */
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      * If we have a toasted datum, forcibly detoast it here to avoid memory
00877      * leakage inside the type's output routine.
00878      */
00879     if (typisvarlena)
00880         val = PointerGetDatum(PG_DETOAST_DATUM(origval));
00881     else
00882         val = origval;
00883 
00884     result = OidOutputFunctionCall(foutoid, val);
00885 
00886     /* Clean up detoasted copy, if any */
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)       /* 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     /* No longer need to worry which context chunk was in... */
00998     return repalloc(pointer, size);
00999 }
01000 
01001 void
01002 SPI_pfree(void *pointer)
01003 {
01004     /* No longer need to worry which context chunk was in... */
01005     pfree(pointer);
01006 }
01007 
01008 void
01009 SPI_freetuple(HeapTuple tuple)
01010 {
01011     /* No longer need to worry which context tuple was in... */
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  * SPI_cursor_open()
01025  *
01026  *  Open a prepared SPI plan as a portal
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     /* build transient ParamListInfo in caller's context */
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     /* done with the transient ParamListInfo */
01043     if (paramLI)
01044         pfree(paramLI);
01045 
01046     return portal;
01047 }
01048 
01049 
01050 /*
01051  * SPI_cursor_open_with_args()
01052  *
01053  * Parse and plan a query and open it as a portal.
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     /* build transient ParamListInfo in executor context */
01085     paramLI = _SPI_convert_params(nargs, argtypes,
01086                                   Values, Nulls);
01087 
01088     _SPI_prepare_plan(src, &plan);
01089 
01090     /* We needn't copy the plan; SPI_cursor_open_internal will do so */
01091 
01092     /* Adjust stack so that SPI_cursor_open_internal doesn't complain */
01093     _SPI_curid--;
01094 
01095     result = SPI_cursor_open_internal(name, &plan, paramLI, read_only);
01096 
01097     /* And clean up */
01098     _SPI_curid++;
01099     _SPI_end_call(true);
01100 
01101     return result;
01102 }
01103 
01104 
01105 /*
01106  * SPI_cursor_open_with_paramlist()
01107  *
01108  *  Same as SPI_cursor_open except that parameters (if any) are passed
01109  *  as a ParamListInfo, which supports dynamic parameter set determination
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  * SPI_cursor_open_internal()
01121  *
01122  *  Common code for SPI_cursor_open variants
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      * Check that the plan is something the Portal code will special-case as
01139      * returning one tupleset.
01140      */
01141     if (!SPI_is_cursor_plan(plan))
01142     {
01143         /* try to give a good error message */
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         /* translator: %s is name of a SQL command, eg INSERT */
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     /* Push the SPI stack */
01160     if (_SPI_begin_call(true) < 0)
01161         elog(ERROR, "SPI_cursor_open called while not connected");
01162 
01163     /* Reset SPI result (note we deliberately don't touch lastoid) */
01164     SPI_processed = 0;
01165     SPI_tuptable = NULL;
01166     _SPI_current->processed = 0;
01167     _SPI_current->tuptable = NULL;
01168 
01169     /* Create the portal */
01170     if (name == NULL || name[0] == '\0')
01171     {
01172         /* Use a random nonconflicting name */
01173         portal = CreateNewPortal();
01174     }
01175     else
01176     {
01177         /* In this path, error if portal of same name already exists */
01178         portal = CreatePortal(name, false, false);
01179     }
01180 
01181     /* Copy the plan's query string into the portal */
01182     query_string = MemoryContextStrdup(PortalGetHeapMemory(portal),
01183                                        plansource->query_string);
01184 
01185     /*
01186      * Setup error traceback support for ereport(), in case GetCachedPlan
01187      * throws an error.
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      * Note: for a saved plan, we mustn't have any failure occur between
01196      * GetCachedPlan and PortalDefineQuery; that would result in leaking our
01197      * plancache refcount.
01198      */
01199 
01200     /* Replan if needed, and increment plan refcount for portal */
01201     cplan = GetCachedPlan(plansource, paramLI, false);
01202     stmt_list = cplan->stmt_list;
01203 
01204     /* Pop the error context stack */
01205     error_context_stack = spierrcontext.previous;
01206 
01207     if (!plan->saved)
01208     {
01209         /*
01210          * We don't want the portal to depend on an unsaved CachedPlanSource,
01211          * so must copy the plan into the portal's context.  An error here
01212          * will result in leaking our refcount on the plan, but it doesn't
01213          * matter because the plan is unsaved and hence transient anyway.
01214          */
01215         oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
01216         stmt_list = copyObject(stmt_list);
01217         MemoryContextSwitchTo(oldcontext);
01218         ReleaseCachedPlan(cplan, false);
01219         cplan = NULL;           /* portal shouldn't depend on cplan */
01220     }
01221 
01222     /*
01223      * Set up the portal.
01224      */
01225     PortalDefineQuery(portal,
01226                       NULL,     /* no statement name */
01227                       query_string,
01228                       plansource->commandTag,
01229                       stmt_list,
01230                       cplan);
01231 
01232     /*
01233      * Set up options for portal.  Default SCROLL type is chosen the same way
01234      * as PerformCursorOpen does it.
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      * Disallow SCROLL with SELECT FOR UPDATE.  This is not redundant with the
01250      * check in transformDeclareCursorStmt because the cursor options might
01251      * not have come through there.
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      * If told to be read-only, we'd better check for read-only queries. This
01266      * can't be done earlier because we need to look at the finished, planned
01267      * queries.  (In particular, we don't want to do it between GetCachedPlan
01268      * and PortalDefineQuery, because throwing an error between those steps
01269      * would result in leaking our plancache refcount.)
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                 /* translator: %s is a SQL statement name */
01283                        errmsg("%s is not allowed in a non-volatile function",
01284                               CreateCommandTag(pstmt))));
01285         }
01286     }
01287 
01288     /* Set up the snapshot to use. */
01289     if (read_only)
01290         snapshot = GetActiveSnapshot();
01291     else
01292     {
01293         CommandCounterIncrement();
01294         snapshot = GetTransactionSnapshot();
01295     }
01296 
01297     /*
01298      * If the plan has parameters, copy them into the portal.  Note that this
01299      * must be done after revalidating the plan, because in dynamic parameter
01300      * cases the set of parameters could have changed during re-parsing.
01301      */
01302     if (paramLI)
01303     {
01304         oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
01305         paramLI = copyParamList(paramLI);
01306         MemoryContextSwitchTo(oldcontext);
01307     }
01308 
01309     /*
01310      * Start portal execution.
01311      */
01312     PortalStart(portal, paramLI, 0, snapshot);
01313 
01314     Assert(portal->strategy != PORTAL_MULTI_QUERY);
01315 
01316     /* Pop the SPI stack */
01317     _SPI_end_call(true);
01318 
01319     /* Return the created portal */
01320     return portal;
01321 }
01322 
01323 
01324 /*
01325  * SPI_cursor_find()
01326  *
01327  *  Find the portal of an existing open cursor
01328  */
01329 Portal
01330 SPI_cursor_find(const char *name)
01331 {
01332     return GetPortalByName(name);
01333 }
01334 
01335 
01336 /*
01337  * SPI_cursor_fetch()
01338  *
01339  *  Fetch rows in a cursor
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     /* we know that the DestSPI receiver doesn't need a destroy call */
01348 }
01349 
01350 
01351 /*
01352  * SPI_cursor_move()
01353  *
01354  *  Move in a cursor
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  * SPI_scroll_cursor_fetch()
01367  *
01368  *  Fetch rows in a scrollable cursor
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     /* we know that the DestSPI receiver doesn't need a destroy call */
01377 }
01378 
01379 
01380 /*
01381  * SPI_scroll_cursor_move()
01382  *
01383  *  Move in a scrollable cursor
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  * SPI_cursor_close()
01394  *
01395  *  Close a cursor
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  * Returns the Oid representing the type id for argument at argIndex. First
01408  * parameter is at index zero.
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  * Returns the number of arguments for the prepared plan.
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  * Returns true if the plan contains exactly one command
01438  * and that command returns tuples to the caller (eg, SELECT or
01439  * INSERT ... RETURNING, but not SELECT ... INTO). In essence,
01440  * the result indicates if the command can be used with SPI_cursor_open
01441  *
01442  * Parameters
01443  *    plan: A plan previously prepared using SPI_prepare
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;           /* not exactly 1 pre-rewrite command */
01460     }
01461     plansource = (CachedPlanSource *) linitial(plan->plancache_list);
01462 
01463     /*
01464      * We used to force revalidation of the cached plan here, but that seems
01465      * unnecessary: invalidation could mean a change in the rowtype of the
01466      * tuples returned by a plan, but not whether it returns tuples at all.
01467      */
01468     SPI_result = 0;
01469 
01470     /* Does it return tuples? */
01471     if (plansource->resultDesc)
01472         return true;
01473 
01474     return false;
01475 }
01476 
01477 /*
01478  * SPI_plan_is_valid --- test whether a SPI plan is currently valid
01479  * (that is, not marked as being in need of revalidation).
01480  *
01481  * See notes for CachedPlanIsValid before using this.
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  * SPI_result_code_string --- convert any SPI return code to a string
01502  *
01503  * This is often useful in error messages.  Most callers will probably
01504  * only pass negative (error-case) codes, but for generality we recognize
01505  * the success codes too.
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     /* Unrecognized code ... return something useful ... */
01564     sprintf(buf, "Unrecognized SPI code %d", code);
01565     return buf;
01566 }
01567 
01568 /*
01569  * SPI_plan_get_plan_sources --- get a SPI plan's underlying list of
01570  * CachedPlanSources.
01571  *
01572  * This is exported so that pl/pgsql can use it (this beats letting pl/pgsql
01573  * look directly into the SPIPlan for itself).  It's not documented in
01574  * spi.sgml because we'd just as soon not have too many places using this.
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  * SPI_plan_get_cached_plan --- get a SPI plan's generic CachedPlan,
01585  * if the SPI plan contains exactly one CachedPlanSource.  If not,
01586  * return NULL.  Caller is responsible for doing ReleaseCachedPlan().
01587  *
01588  * This is exported so that pl/pgsql can use it (this beats letting pl/pgsql
01589  * look directly into the SPIPlan for itself).  It's not documented in
01590  * spi.sgml because we'd just as soon not have too many places using this.
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     /* Can't support one-shot plans here */
01602     if (plan->oneshot)
01603         return NULL;
01604 
01605     /* Must have exactly one CachedPlanSource */
01606     if (list_length(plan->plancache_list) != 1)
01607         return NULL;
01608     plansource = (CachedPlanSource *) linitial(plan->plancache_list);
01609 
01610     /* Setup error traceback support for ereport() */
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     /* Get the generic plan for the query */
01617     cplan = GetCachedPlan(plansource, NULL, plan->saved);
01618     Assert(cplan == plansource->gplan);
01619 
01620     /* Pop the error context stack */
01621     error_context_stack = spierrcontext.previous;
01622 
01623     return cplan;
01624 }
01625 
01626 
01627 /* =================== private functions =================== */
01628 
01629 /*
01630  * spi_dest_startup
01631  *      Initialize to receive tuples from Executor into SPITupleTable
01632  *      of current SPI procedure
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      * When called by Executor _SPI_curid expected to be equal to
01643      * _SPI_connected
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();    /* switch to procedure memory context */
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  * spi_printtup
01674  *      store tuple retrieved by Executor into SPITupleTable
01675  *      of current SPI procedure
01676  */
01677 void
01678 spi_printtup(TupleTableSlot *slot, DestReceiver *self)
01679 {
01680     SPITupleTable *tuptable;
01681     MemoryContext oldcxt;
01682 
01683     /*
01684      * When called by Executor _SPI_curid expected to be equal to
01685      * _SPI_connected
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  * Static functions
01715  */
01716 
01717 /*
01718  * Parse and analyze a querystring.
01719  *
01720  * At entry, plan->argtypes and plan->nargs (or alternatively plan->parserSetup
01721  * and plan->parserSetupArg) must be valid, as must plan->cursor_options.
01722  *
01723  * Results are stored into *plan (specifically, plan->plancache_list).
01724  * Note that the result data is all in CurrentMemoryContext or child contexts
01725  * thereof; in practice this means it is in the SPI executor context, and
01726  * what we are creating is a "temporary" SPIPlan.  Cruft generated during
01727  * parsing is also left in CurrentMemoryContext.
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      * Setup error traceback support for ereport()
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      * Parse the request string into a list of raw parse trees.
01747      */
01748     raw_parsetree_list = pg_parse_query(src);
01749 
01750     /*
01751      * Do parse analysis and rule rewrite for each raw parsetree, storing the
01752      * results into unsaved plancache entries.
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          * Create the CachedPlanSource before we do parse analysis, since it
01764          * needs to see the unmodified raw parse tree.
01765          */
01766         plansource = CreateCachedPlan(parsetree,
01767                                       src,
01768                                       CreateCommandTag(parsetree));
01769 
01770         /*
01771          * Parameter datatypes are driven by parserSetup hook if provided,
01772          * otherwise we use the fixed parameter list.
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         /* Finish filling in the CachedPlanSource */
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);      /* not fixed result */
01800 
01801         plancache_list = lappend(plancache_list, plansource);
01802     }
01803 
01804     plan->plancache_list = plancache_list;
01805     plan->oneshot = false;
01806 
01807     /*
01808      * Pop the error context stack
01809      */
01810     error_context_stack = spierrcontext.previous;
01811 }
01812 
01813 /*
01814  * Parse, but don't analyze, a querystring.
01815  *
01816  * This is a stripped-down version of _SPI_prepare_plan that only does the
01817  * initial raw parsing.  It creates "one shot" CachedPlanSources
01818  * that still require parse analysis before execution is possible.
01819  *
01820  * The advantage of using the "one shot" form of CachedPlanSource is that
01821  * we eliminate data copying and invalidation overhead.  Postponing parse
01822  * analysis also prevents issues if some of the raw parsetrees are DDL
01823  * commands that affect validity of later parsetrees.  Both of these
01824  * attributes are good things for SPI_execute() and similar cases.
01825  *
01826  * Results are stored into *plan (specifically, plan->plancache_list).
01827  * Note that the result data is all in CurrentMemoryContext or child contexts
01828  * thereof; in practice this means it is in the SPI executor context, and
01829  * what we are creating is a "temporary" SPIPlan.  Cruft generated during
01830  * parsing is also left in CurrentMemoryContext.
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      * Setup error traceback support for ereport()
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      * Parse the request string into a list of raw parse trees.
01850      */
01851     raw_parsetree_list = pg_parse_query(src);
01852 
01853     /*
01854      * Construct plancache entries, but don't do parse analysis yet.
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      * Pop the error context stack
01875      */
01876     error_context_stack = spierrcontext.previous;
01877 }
01878 
01879 /*
01880  * Execute the given plan with the given parameter values
01881  *
01882  * snapshot: query snapshot to use, or InvalidSnapshot for the normal
01883  *      behavior of taking a new snapshot for each query.
01884  * crosscheck_snapshot: for RI use, all others pass InvalidSnapshot
01885  * read_only: TRUE for read-only execution (no CommandCounterIncrement)
01886  * fire_triggers: TRUE to fire AFTER triggers at end of query (normal case);
01887  *      FALSE means any AFTER triggers are postponed to end of outer query
01888  * tcount: execution tuple-count limit, or 0 for none
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      * Setup error traceback support for ereport()
01907      */
01908     spierrcontext.callback = _SPI_error_callback;
01909     spierrcontext.arg = NULL;   /* we'll fill this below */
01910     spierrcontext.previous = error_context_stack;
01911     error_context_stack = &spierrcontext;
01912 
01913     /*
01914      * We support four distinct snapshot management behaviors:
01915      *
01916      * snapshot != InvalidSnapshot, read_only = true: use exactly the given
01917      * snapshot.
01918      *
01919      * snapshot != InvalidSnapshot, read_only = false: use the given snapshot,
01920      * modified by advancing its command ID before each querytree.
01921      *
01922      * snapshot == InvalidSnapshot, read_only = true: use the entry-time
01923      * ActiveSnapshot, if any (if there isn't one, we run with no snapshot).
01924      *
01925      * snapshot == InvalidSnapshot, read_only = false: take a full new
01926      * snapshot for each user command, and advance its command ID before each
01927      * querytree within the command.
01928      *
01929      * In the first two cases, we can just push the snap onto the stack once
01930      * for the whole plan list.
01931      */
01932     if (snapshot != InvalidSnapshot)
01933     {
01934         if (read_only)
01935         {
01936             PushActiveSnapshot(snapshot);
01937             pushed_active_snap = true;
01938         }
01939         else
01940         {
01941             /* Make sure we have a private copy of the snapshot to modify */
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          * If this is a one-shot plan, we still need to do parse analysis.
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              * Parameter datatypes are driven by parserSetup hook if provided,
01966              * otherwise we use the fixed parameter list.
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             /* Finish filling in the CachedPlanSource */
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);      /* not fixed result */
01994         }
01995 
01996         /*
01997          * Replan if needed, and increment plan refcount.  If it's a saved
01998          * plan, the refcount must be backed by the CurrentResourceOwner.
01999          */
02000         cplan = GetCachedPlan(plansource, paramLI, plan->saved);
02001         stmt_list = cplan->stmt_list;
02002 
02003         /*
02004          * In the default non-read-only case, get a new snapshot, replacing
02005          * any that we pushed in a previous cycle.
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                 /* utilities are canSetTag if only thing in list */
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                 /* translator: %s is a SQL statement name */
02055                        errmsg("%s is not allowed in a non-volatile function",
02056                               CreateCommandTag(stmt))));
02057 
02058             /*
02059              * If not read-only mode, advance the command counter before each
02060              * command and update the snapshot.
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                 /* Update "processed" if stmt returned tuples */
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                  * Some utility statements return a row count, even though the
02110                  * tuples are not returned to the caller.
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                      * For historical reasons, if CREATE TABLE AS was spelled
02120                      * as SELECT INTO, return a special return code.
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              * The last canSetTag query sets the status values returned to the
02135              * caller.  Be careful to free any tuptables not returned, to
02136              * avoid intratransaction memory leak.
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             /* we know that the receiver doesn't need a destroy call */
02152             if (res < 0)
02153             {
02154                 my_res = res;
02155                 goto fail;
02156             }
02157         }
02158 
02159         /* Done with this plan, so release refcount */
02160         ReleaseCachedPlan(cplan, plan->saved);
02161         cplan = NULL;
02162 
02163         /*
02164          * If not read-only mode, advance the command counter after the last
02165          * command.  This ensures that its effects are visible, in case it was
02166          * DDL that would affect the next CachedPlanSource.
02167          */
02168         if (!read_only)
02169             CommandCounterIncrement();
02170     }
02171 
02172 fail:
02173 
02174     /* Pop the snapshot off the stack if we pushed one */
02175     if (pushed_active_snap)
02176         PopActiveSnapshot();
02177 
02178     /* We no longer need the cached plan refcount, if any */
02179     if (cplan)
02180         ReleaseCachedPlan(cplan, plan->saved);
02181 
02182     /*
02183      * Pop the error context stack
02184      */
02185     error_context_stack = spierrcontext.previous;
02186 
02187     /* Save results for caller */
02188     SPI_processed = my_processed;
02189     SPI_lastoid = my_lastoid;
02190     SPI_tuptable = my_tuptable;
02191 
02192     /* tuptable now is caller's responsibility, not SPI's */
02193     _SPI_current->tuptable = NULL;
02194 
02195     /*
02196      * If none of the queries had canSetTag, return SPI_OK_REWRITTEN. Prior to
02197      * 8.4, we used return the last query's result code, but not its auxiliary
02198      * results, but that's confusing.
02199      */
02200     if (my_res == 0)
02201         my_res = SPI_OK_REWRITTEN;
02202 
02203     return my_res;
02204 }
02205 
02206 /*
02207  * Convert arrays of query parameters to form wanted by planner and executor
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         /* sizeof(ParamListInfoData) includes the first array element */
02220         paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
02221                                       (nargs - 1) * sizeof(ParamExternData));
02222         /* we have static list of params, so no hooks needed */
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 = &paramLI->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                 /* Don't return SPI_OK_SELECT if we're discarding result */
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     /* Select execution options */
02291     if (fire_triggers)
02292         eflags = 0;             /* default run-to-completion flags */
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     /* FreeQueryDesc is done by the caller */
02313 
02314 #ifdef SPI_EXECUTOR_STATS
02315     if (ShowExecutorStats)
02316         ShowUsage("SPI EXECUTOR STATS");
02317 #endif
02318 
02319     return res;
02320 }
02321 
02322 /*
02323  * _SPI_error_callback
02324  *
02325  * Add context information when a query invoked via SPI fails
02326  */
02327 static void
02328 _SPI_error_callback(void *arg)
02329 {
02330     const char *query = (const char *) arg;
02331     int         syntaxerrposition;
02332 
02333     /*
02334      * If there is a syntax error position, convert to internal syntax error;
02335      * otherwise treat the query as an item of context stack
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  * _SPI_cursor_operation()
02350  *
02351  *  Do a FETCH or MOVE in a cursor
02352  */
02353 static void
02354 _SPI_cursor_operation(Portal portal, FetchDirection direction, long count,
02355                       DestReceiver *dest)
02356 {
02357     long        nfetched;
02358 
02359     /* Check that the portal is valid */
02360     if (!PortalIsValid(portal))
02361         elog(ERROR, "invalid portal in SPI cursor operation");
02362 
02363     /* Push the SPI stack */
02364     if (_SPI_begin_call(true) < 0)
02365         elog(ERROR, "SPI cursor operation called while not connected");
02366 
02367     /* Reset the SPI result (note we deliberately don't touch lastoid) */
02368     SPI_processed = 0;
02369     SPI_tuptable = NULL;
02370     _SPI_current->processed = 0;
02371     _SPI_current->tuptable = NULL;
02372 
02373     /* Run the cursor */
02374     nfetched = PortalRunFetch(portal,
02375                               direction,
02376                               count,
02377                               dest);
02378 
02379     /*
02380      * Think not to combine this store with the preceding function call. If
02381      * the portal contains calls to functions that use SPI, then SPI_stack is
02382      * likely to move around while the portal runs.  When control returns,
02383      * _SPI_current will point to the correct stack entry... but the pointer
02384      * may be different than it was beforehand. So we must be sure to re-fetch
02385      * the pointer after the function call completes.
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     /* Put the result into place for access by caller */
02393     SPI_processed = _SPI_current->processed;
02394     SPI_tuptable = _SPI_current->tuptable;
02395 
02396     /* tuptable now is caller's responsibility, not SPI's */
02397     _SPI_current->tuptable = NULL;
02398 
02399     /* Pop the SPI stack */
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  * _SPI_begin_call: begin a SPI operation within a connected procedure
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)                /* switch to the Executor memory context */
02429         _SPI_execmem();
02430 
02431     return 0;
02432 }
02433 
02434 /*
02435  * _SPI_end_call: end a SPI operation within a connected procedure
02436  *
02437  * Note: this currently has no failure return cases, so callers don't check
02438  */
02439 static int
02440 _SPI_end_call(bool procmem)
02441 {
02442     /*
02443      * We're returning to procedure where _SPI_curid == _SPI_connected - 1
02444      */
02445     _SPI_curid--;
02446 
02447     if (procmem)                /* switch to the procedure memory context */
02448     {
02449         _SPI_procmem();
02450         /* and free Executor memory */
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)       /* spi_dest_startup was not called */
02465         failed = true;
02466     else if (processed != (tuptable->alloced - tuptable->free))
02467         failed = true;
02468 
02469     return failed;
02470 }
02471 
02472 /*
02473  * Convert a "temporary" SPIPlan into an "unsaved" plan.
02474  *
02475  * The passed _SPI_plan struct is on the stack, and all its subsidiary data
02476  * is in or under the current SPI executor context.  Copy the plan into the
02477  * SPI procedure context so it will survive _SPI_end_call().  To minimize
02478  * data copying, this destructively modifies the input plan, by taking the
02479  * plancache entries away from it and reparenting them to the new SPIPlan.
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     /* Assert the input is a temporary SPIPlan */
02491     Assert(plan->magic == _SPI_PLAN_MAGIC);
02492     Assert(plan->plancxt == NULL);
02493     /* One-shot plans can't be saved */
02494     Assert(!plan->oneshot);
02495 
02496     /*
02497      * Create a memory context for the plan, underneath the procedure context.
02498      * We don't expect the plan to be very large, so use smaller-than-default
02499      * alloc parameters.
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     /* Copy the SPI_plan struct and subsidiary data into the new context */
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      * Reparent all the CachedPlanSources into the procedure context.  In
02529      * theory this could fail partway through due to the pallocs, but we don't
02530      * care too much since both the procedure context and the executor context
02531      * would go away on error.
02532      */
02533     foreach(lc, plan->plancache_list)
02534     {
02535         CachedPlanSource *plansource = (CachedPlanSource *) lfirst(lc);
02536 
02537         CachedPlanSetParentContext(plansource, parentcxt);
02538 
02539         /* Build new list, with list cells in plancxt */
02540         newplan->plancache_list = lappend(newplan->plancache_list, plansource);
02541     }
02542 
02543     MemoryContextSwitchTo(oldcxt);
02544 
02545     /* For safety, unlink the CachedPlanSources from the temporary plan */
02546     plan->plancache_list = NIL;
02547 
02548     return newplan;
02549 }
02550 
02551 /*
02552  * Make a "saved" copy of the given plan.
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     /* One-shot plans can't be saved */
02563     Assert(!plan->oneshot);
02564 
02565     /*
02566      * Create a memory context for the plan.  We don't expect the plan to be
02567      * very large, so use smaller-than-default alloc parameters.  It's a
02568      * transient context until we finish copying everything.
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     /* Copy the SPI plan into its own context */
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     /* Copy all the plancache entries */
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      * Mark it saved, reparent it under CacheMemoryContext, and mark all the
02610      * component CachedPlanSources as saved.  This sequence cannot fail
02611      * partway through, so there's no risk of long-term memory leakage.
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 }