1997-08-29 11:05:57 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* spi.h
|
2007-03-16 00:12:07 +01:00
|
|
|
* Server Programming Interface public declarations
|
1997-09-07 07:04:48 +02:00
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
2007-03-16 00:12:07 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
|
|
*
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/include/executor/spi.h
|
1997-08-29 11:05:57 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
#ifndef SPI_H
|
1997-08-29 11:05:57 +02:00
|
|
|
#define SPI_H
|
|
|
|
|
Prevent leakage of SPI tuple tables during subtransaction abort.
plpgsql often just remembers SPI-result tuple tables in local variables,
and has no mechanism for freeing them if an ereport(ERROR) causes an escape
out of the execution function whose local variable it is. In the original
coding, that wasn't a problem because the tuple table would be cleaned up
when the function's SPI context went away during transaction abort.
However, once plpgsql grew the ability to trap exceptions, repeated
trapping of errors within a function could result in significant
intra-function-call memory leakage, as illustrated in bug #8279 from
Chad Wagner.
We could fix this locally in plpgsql with a bunch of PG_TRY/PG_CATCH
coding, but that would be tedious, probably slow, and prone to bugs of
omission; moreover it would do nothing for similar risks elsewhere.
What seems like a better plan is to make SPI itself responsible for
freeing tuple tables at subtransaction abort. This patch attacks the
problem that way, keeping a list of live tuple tables within each SPI
function context. Currently, such freeing is automatic for tuple tables
made within the failed subtransaction. We might later add a SPI call to
mark a tuple table as not to be freed this way, allowing callers to opt
out; but until someone exhibits a clear use-case for such behavior, it
doesn't seem worth bothering.
A very useful side-effect of this change is that SPI_freetuptable() can
now defend itself against bad calls, such as duplicate free requests;
this should make things more robust in many places. (In particular,
this reduces the risks involved if a third-party extension contains
now-redundant SPI_freetuptable() calls in error cleanup code.)
Even though the leakage problem is of long standing, it seems imprudent
to back-patch this into stable branches, since it does represent an API
semantics change for SPI users. We'll patch this in 9.3, but live with
the leakage in older branches.
2013-07-25 22:45:43 +02:00
|
|
|
#include "lib/ilist.h"
|
2011-09-04 07:13:16 +02:00
|
|
|
#include "nodes/parsenodes.h"
|
2003-03-10 04:53:52 +01:00
|
|
|
#include "utils/portal.h"
|
1997-08-29 11:05:57 +02:00
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
|
|
|
|
typedef struct SPITupleTable
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2001-05-21 16:22:19 +02:00
|
|
|
MemoryContext tuptabcxt; /* memory context of result table */
|
Widen query numbers-of-tuples-processed counters to uint64.
This patch widens SPI_processed, EState's es_processed field, PortalData's
portalPos field, FuncCallContext's call_cntr and max_calls fields,
ExecutorRun's count argument, PortalRunFetch's result, and the max number
of rows in a SPITupleTable to uint64, and deals with (I hope) all the
ensuing fallout. Some of these values were declared uint32 before, and
others "long".
I also removed PortalData's posOverflow field, since that logic seems
pretty useless given that portalPos is now always 64 bits.
The user-visible results are that command tags for SELECT etc will
correctly report tuple counts larger than 4G, as will plpgsql's GET
GET DIAGNOSTICS ... ROW_COUNT command. Queries processing more tuples
than that are still not exactly the norm, but they're becoming more
common.
Most values associated with FETCH/MOVE distances, such as PortalRun's count
argument and the count argument of most SPI functions that have one, remain
declared as "long". It's not clear whether it would be worth promoting
those to int64; but it would definitely be a large dollop of additional
API churn on top of this, and it would only help 32-bit platforms which
seem relatively less likely to see any benefit.
Andreas Scherbaum, reviewed by Christian Ullrich, additional hacking by me
2016-03-12 22:05:10 +01:00
|
|
|
uint64 alloced; /* # of alloced vals */
|
|
|
|
uint64 free; /* # of free vals */
|
1997-09-08 04:41:22 +02:00
|
|
|
TupleDesc tupdesc; /* tuple descriptor */
|
|
|
|
HeapTuple *vals; /* tuples */
|
Prevent leakage of SPI tuple tables during subtransaction abort.
plpgsql often just remembers SPI-result tuple tables in local variables,
and has no mechanism for freeing them if an ereport(ERROR) causes an escape
out of the execution function whose local variable it is. In the original
coding, that wasn't a problem because the tuple table would be cleaned up
when the function's SPI context went away during transaction abort.
However, once plpgsql grew the ability to trap exceptions, repeated
trapping of errors within a function could result in significant
intra-function-call memory leakage, as illustrated in bug #8279 from
Chad Wagner.
We could fix this locally in plpgsql with a bunch of PG_TRY/PG_CATCH
coding, but that would be tedious, probably slow, and prone to bugs of
omission; moreover it would do nothing for similar risks elsewhere.
What seems like a better plan is to make SPI itself responsible for
freeing tuple tables at subtransaction abort. This patch attacks the
problem that way, keeping a list of live tuple tables within each SPI
function context. Currently, such freeing is automatic for tuple tables
made within the failed subtransaction. We might later add a SPI call to
mark a tuple table as not to be freed this way, allowing callers to opt
out; but until someone exhibits a clear use-case for such behavior, it
doesn't seem worth bothering.
A very useful side-effect of this change is that SPI_freetuptable() can
now defend itself against bad calls, such as duplicate free requests;
this should make things more robust in many places. (In particular,
this reduces the risks involved if a third-party extension contains
now-redundant SPI_freetuptable() calls in error cleanup code.)
Even though the leakage problem is of long standing, it seems imprudent
to back-patch this into stable branches, since it does represent an API
semantics change for SPI users. We'll patch this in 9.3, but live with
the leakage in older branches.
2013-07-25 22:45:43 +02:00
|
|
|
slist_node next; /* link for internal bookkeeping */
|
|
|
|
SubTransactionId subid; /* subxact in which tuptable was created */
|
1998-02-26 05:46:47 +01:00
|
|
|
} SPITupleTable;
|
1997-08-29 11:05:57 +02:00
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
/* Plans are opaque structs for standard users of SPI */
|
|
|
|
typedef struct _SPI_plan *SPIPlanPtr;
|
|
|
|
|
2001-08-02 20:08:43 +02:00
|
|
|
#define SPI_ERROR_CONNECT (-1)
|
|
|
|
#define SPI_ERROR_COPY (-2)
|
|
|
|
#define SPI_ERROR_OPUNKNOWN (-3)
|
|
|
|
#define SPI_ERROR_UNCONNECTED (-4)
|
2007-11-15 22:14:46 +01:00
|
|
|
#define SPI_ERROR_CURSOR (-5) /* not used anymore */
|
2001-08-02 20:08:43 +02:00
|
|
|
#define SPI_ERROR_ARGUMENT (-6)
|
|
|
|
#define SPI_ERROR_PARAM (-7)
|
|
|
|
#define SPI_ERROR_TRANSACTION (-8)
|
|
|
|
#define SPI_ERROR_NOATTRIBUTE (-9)
|
|
|
|
#define SPI_ERROR_NOOUTFUNC (-10)
|
|
|
|
#define SPI_ERROR_TYPUNKNOWN (-11)
|
1997-08-29 11:05:57 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
#define SPI_OK_CONNECT 1
|
|
|
|
#define SPI_OK_FINISH 2
|
|
|
|
#define SPI_OK_FETCH 3
|
|
|
|
#define SPI_OK_UTILITY 4
|
|
|
|
#define SPI_OK_SELECT 5
|
|
|
|
#define SPI_OK_SELINTO 6
|
|
|
|
#define SPI_OK_INSERT 7
|
|
|
|
#define SPI_OK_DELETE 8
|
|
|
|
#define SPI_OK_UPDATE 9
|
|
|
|
#define SPI_OK_CURSOR 10
|
2006-10-04 02:30:14 +02:00
|
|
|
#define SPI_OK_INSERT_RETURNING 11
|
|
|
|
#define SPI_OK_DELETE_RETURNING 12
|
|
|
|
#define SPI_OK_UPDATE_RETURNING 13
|
2009-01-21 12:02:40 +01:00
|
|
|
#define SPI_OK_REWRITTEN 14
|
1997-09-04 15:26:19 +02:00
|
|
|
|
Simplify code by getting rid of SPI_push, SPI_pop, SPI_restore_connection.
The idea behind SPI_push was to allow transitioning back into an
"unconnected" state when a SPI-using procedure calls unrelated code that
might or might not invoke SPI. That sounds good, but in practice the only
thing it does for us is to catch cases where a called SPI-using function
forgets to call SPI_connect --- which is a highly improbable failure mode,
since it would be exposed immediately by direct testing of said function.
As against that, we've had multiple bugs induced by forgetting to call
SPI_push/SPI_pop around code that might invoke SPI-using functions; these
are much harder to catch and indeed have gone undetected for years in some
cases. And we've had to band-aid around some problems of this ilk by
introducing conditional push/pop pairs in some places, which really kind
of defeats the purpose altogether; if we can't draw bright lines between
connected and unconnected code, what's the point?
Hence, get rid of SPI_push[_conditional], SPI_pop[_conditional], and the
underlying state variable _SPI_curid. It turns out SPI_restore_connection
can go away too, which is a nice side benefit since it was never more than
a kluge. Provide no-op macros for the deleted functions so as to avoid an
API break for external modules.
A side effect of this removal is that SPI_palloc and allied functions no
longer permit being called when unconnected; they'll throw an error
instead. The apparent usefulness of the previous behavior was a mirage
as well, because it was depended on by only a few places (which I fixed in
preceding commits), and it posed a risk of allocations being unexpectedly
long-lived if someone forgot a SPI_push call.
Discussion: <20808.1478481403@sss.pgh.pa.us>
2016-11-08 23:39:45 +01:00
|
|
|
/* These used to be functions, now just no-ops for backwards compatibility */
|
|
|
|
#define SPI_push() ((void) 0)
|
|
|
|
#define SPI_pop() ((void) 0)
|
|
|
|
#define SPI_push_conditional() false
|
|
|
|
#define SPI_pop_conditional(pushed) ((void) 0)
|
|
|
|
#define SPI_restore_connection() ((void) 0)
|
|
|
|
|
Widen query numbers-of-tuples-processed counters to uint64.
This patch widens SPI_processed, EState's es_processed field, PortalData's
portalPos field, FuncCallContext's call_cntr and max_calls fields,
ExecutorRun's count argument, PortalRunFetch's result, and the max number
of rows in a SPITupleTable to uint64, and deals with (I hope) all the
ensuing fallout. Some of these values were declared uint32 before, and
others "long".
I also removed PortalData's posOverflow field, since that logic seems
pretty useless given that portalPos is now always 64 bits.
The user-visible results are that command tags for SELECT etc will
correctly report tuple counts larger than 4G, as will plpgsql's GET
GET DIAGNOSTICS ... ROW_COUNT command. Queries processing more tuples
than that are still not exactly the norm, but they're becoming more
common.
Most values associated with FETCH/MOVE distances, such as PortalRun's count
argument and the count argument of most SPI functions that have one, remain
declared as "long". It's not clear whether it would be worth promoting
those to int64; but it would definitely be a large dollop of additional
API churn on top of this, and it would only help 32-bit platforms which
seem relatively less likely to see any benefit.
Andreas Scherbaum, reviewed by Christian Ullrich, additional hacking by me
2016-03-12 22:05:10 +01:00
|
|
|
extern PGDLLIMPORT uint64 SPI_processed;
|
2007-07-25 14:22:54 +02:00
|
|
|
extern PGDLLIMPORT Oid SPI_lastoid;
|
|
|
|
extern PGDLLIMPORT SPITupleTable *SPI_tuptable;
|
|
|
|
extern PGDLLIMPORT int SPI_result;
|
1997-08-29 11:05:57 +02:00
|
|
|
|
1997-09-08 04:41:22 +02:00
|
|
|
extern int SPI_connect(void);
|
|
|
|
extern int SPI_finish(void);
|
2005-05-02 02:37:07 +02:00
|
|
|
extern int SPI_execute(const char *src, bool read_only, long tcount);
|
2007-11-15 22:14:46 +01:00
|
|
|
extern int SPI_execute_plan(SPIPlanPtr plan, Datum *Values, const char *Nulls,
|
2005-10-15 04:49:52 +02:00
|
|
|
bool read_only, long tcount);
|
2009-11-04 23:26:08 +01:00
|
|
|
extern int SPI_execute_plan_with_paramlist(SPIPlanPtr plan,
|
2010-02-26 03:01:40 +01:00
|
|
|
ParamListInfo params,
|
|
|
|
bool read_only, long tcount);
|
2005-05-02 02:37:07 +02:00
|
|
|
extern int SPI_exec(const char *src, long tcount);
|
2007-11-15 22:14:46 +01:00
|
|
|
extern int SPI_execp(SPIPlanPtr plan, Datum *Values, const char *Nulls,
|
2005-10-15 04:49:52 +02:00
|
|
|
long tcount);
|
2007-11-15 22:14:46 +01:00
|
|
|
extern int SPI_execute_snapshot(SPIPlanPtr plan,
|
2005-10-15 04:49:52 +02:00
|
|
|
Datum *Values, const char *Nulls,
|
|
|
|
Snapshot snapshot,
|
|
|
|
Snapshot crosscheck_snapshot,
|
2007-08-15 21:15:47 +02:00
|
|
|
bool read_only, bool fire_triggers, long tcount);
|
2009-06-11 16:49:15 +02:00
|
|
|
extern int SPI_execute_with_args(const char *src,
|
|
|
|
int nargs, Oid *argtypes,
|
|
|
|
Datum *Values, const char *Nulls,
|
|
|
|
bool read_only, long tcount);
|
2007-03-16 00:12:07 +01:00
|
|
|
extern SPIPlanPtr SPI_prepare(const char *src, int nargs, Oid *argtypes);
|
2007-04-16 03:14:58 +02:00
|
|
|
extern SPIPlanPtr SPI_prepare_cursor(const char *src, int nargs, Oid *argtypes,
|
2007-11-15 22:14:46 +01:00
|
|
|
int cursorOptions);
|
2009-11-04 23:26:08 +01:00
|
|
|
extern SPIPlanPtr SPI_prepare_params(const char *src,
|
2010-02-26 03:01:40 +01:00
|
|
|
ParserSetupHook parserSetup,
|
|
|
|
void *parserSetupArg,
|
|
|
|
int cursorOptions);
|
2011-09-16 06:42:53 +02:00
|
|
|
extern int SPI_keepplan(SPIPlanPtr plan);
|
2007-03-16 00:12:07 +01:00
|
|
|
extern SPIPlanPtr SPI_saveplan(SPIPlanPtr plan);
|
|
|
|
extern int SPI_freeplan(SPIPlanPtr plan);
|
1997-09-04 15:26:19 +02:00
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
extern Oid SPI_getargtypeid(SPIPlanPtr plan, int argIndex);
|
|
|
|
extern int SPI_getargcount(SPIPlanPtr plan);
|
|
|
|
extern bool SPI_is_cursor_plan(SPIPlanPtr plan);
|
2008-09-16 01:37:40 +02:00
|
|
|
extern bool SPI_plan_is_valid(SPIPlanPtr plan);
|
2004-07-31 22:55:45 +02:00
|
|
|
extern const char *SPI_result_code_string(int code);
|
2004-03-05 01:47:01 +01:00
|
|
|
|
Fix plpgsql's reporting of plan-time errors in possibly-simple expressions.
exec_simple_check_plan and exec_eval_simple_expr attempted to call
GetCachedPlan directly. This meant that if an error was thrown during
planning, the resulting context traceback would not include the line
normally contributed by _SPI_error_callback. This is already inconsistent,
but just to be really odd, a re-execution of the very same expression
*would* show the additional context line, because we'd already have cached
the plan and marked the expression as non-simple.
The problem is easy to demonstrate in 9.2 and HEAD because planning of a
cached plan doesn't occur at all until GetCachedPlan is done. In earlier
versions, it could only be an issue if initial planning had succeeded, then
a replan was forced (already somewhat improbable for a simple expression),
and the replan attempt failed. Since the issue is mainly cosmetic in older
branches anyway, it doesn't seem worth the risk of trying to fix it there.
It is worth fixing in 9.2 since the instability of the context printout can
affect the results of GET STACKED DIAGNOSTICS, as per a recent discussion
on pgsql-novice.
To fix, introduce a SPI function that wraps GetCachedPlan while installing
the correct callback function. Use this instead of calling GetCachedPlan
directly from plpgsql.
Also introduce a wrapper function for extracting a SPI plan's
CachedPlanSource list. This lets us stop including spi_priv.h in
pl_exec.c, which was never a very good idea from a modularity standpoint.
In passing, fix a similar inconsistency that could occur in SPI_cursor_open,
which was also calling GetCachedPlan without setting up a context callback.
2013-01-31 02:02:23 +01:00
|
|
|
extern List *SPI_plan_get_plan_sources(SPIPlanPtr plan);
|
|
|
|
extern CachedPlan *SPI_plan_get_cached_plan(SPIPlanPtr plan);
|
|
|
|
|
1997-09-12 10:37:52 +02:00
|
|
|
extern HeapTuple SPI_copytuple(HeapTuple tuple);
|
2004-04-01 23:28:47 +02:00
|
|
|
extern HeapTupleHeader SPI_returntuple(HeapTuple tuple, TupleDesc tupdesc);
|
1998-09-01 06:40:42 +02:00
|
|
|
extern HeapTuple SPI_modifytuple(Relation rel, HeapTuple tuple, int natts,
|
2002-12-30 23:10:54 +01:00
|
|
|
int *attnum, Datum *Values, const char *Nulls);
|
|
|
|
extern int SPI_fnumber(TupleDesc tupdesc, const char *fname);
|
1997-09-11 09:24:37 +02:00
|
|
|
extern char *SPI_fname(TupleDesc tupdesc, int fnumber);
|
1997-09-08 04:41:22 +02:00
|
|
|
extern char *SPI_getvalue(HeapTuple tuple, TupleDesc tupdesc, int fnumber);
|
1998-02-26 05:46:47 +01:00
|
|
|
extern Datum SPI_getbinval(HeapTuple tuple, TupleDesc tupdesc, int fnumber, bool *isnull);
|
1997-09-08 04:41:22 +02:00
|
|
|
extern char *SPI_gettype(TupleDesc tupdesc, int fnumber);
|
|
|
|
extern Oid SPI_gettypeid(TupleDesc tupdesc, int fnumber);
|
|
|
|
extern char *SPI_getrelname(Relation rel);
|
2005-03-29 04:53:53 +02:00
|
|
|
extern char *SPI_getnspname(Relation rel);
|
1998-02-26 05:46:47 +01:00
|
|
|
extern void *SPI_palloc(Size size);
|
|
|
|
extern void *SPI_repalloc(void *pointer, Size size);
|
|
|
|
extern void SPI_pfree(void *pointer);
|
Support "expanded" objects, particularly arrays, for better performance.
This patch introduces the ability for complex datatypes to have an
in-memory representation that is different from their on-disk format.
On-disk formats are typically optimized for minimal size, and in any case
they can't contain pointers, so they are often not well-suited for
computation. Now a datatype can invent an "expanded" in-memory format
that is better suited for its operations, and then pass that around among
the C functions that operate on the datatype. There are also provisions
(rudimentary as yet) to allow an expanded object to be modified in-place
under suitable conditions, so that operations like assignment to an element
of an array need not involve copying the entire array.
The initial application for this feature is arrays, but it is not hard
to foresee using it for other container types like JSON, XML and hstore.
I have hopes that it will be useful to PostGIS as well.
In this initial implementation, a few heuristics have been hard-wired
into plpgsql to improve performance for arrays that are stored in
plpgsql variables. We would like to generalize those hacks so that
other datatypes can obtain similar improvements, but figuring out some
appropriate APIs is left as a task for future work. (The heuristics
themselves are probably not optimal yet, either, as they sometimes
force expansion of arrays that would be better left alone.)
Preliminary performance testing shows impressive speed gains for plpgsql
functions that do element-by-element access or update of large arrays.
There are other cases that get a little slower, as a result of added array
format conversions; but we can hope to improve anything that's annoyingly
bad. In any case most applications should see a net win.
Tom Lane, reviewed by Andres Freund
2015-05-14 18:08:40 +02:00
|
|
|
extern Datum SPI_datumTransfer(Datum value, bool typByVal, int typLen);
|
1999-12-16 23:20:03 +01:00
|
|
|
extern void SPI_freetuple(HeapTuple pointer);
|
2001-05-21 16:22:19 +02:00
|
|
|
extern void SPI_freetuptable(SPITupleTable *tuptable);
|
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
extern Portal SPI_cursor_open(const char *name, SPIPlanPtr plan,
|
2004-09-13 22:10:13 +02:00
|
|
|
Datum *Values, const char *Nulls, bool read_only);
|
2008-04-01 05:09:30 +02:00
|
|
|
extern Portal SPI_cursor_open_with_args(const char *name,
|
2009-06-11 16:49:15 +02:00
|
|
|
const char *src,
|
|
|
|
int nargs, Oid *argtypes,
|
|
|
|
Datum *Values, const char *Nulls,
|
|
|
|
bool read_only, int cursorOptions);
|
2009-11-04 23:26:08 +01:00
|
|
|
extern Portal SPI_cursor_open_with_paramlist(const char *name, SPIPlanPtr plan,
|
|
|
|
ParamListInfo params, bool read_only);
|
2002-12-30 23:10:54 +01:00
|
|
|
extern Portal SPI_cursor_find(const char *name);
|
2006-09-03 05:19:45 +02:00
|
|
|
extern void SPI_cursor_fetch(Portal portal, bool forward, long count);
|
|
|
|
extern void SPI_cursor_move(Portal portal, bool forward, long count);
|
2007-04-16 03:14:58 +02:00
|
|
|
extern void SPI_scroll_cursor_fetch(Portal, FetchDirection direction, long count);
|
|
|
|
extern void SPI_scroll_cursor_move(Portal, FetchDirection direction, long count);
|
2001-10-25 07:50:21 +02:00
|
|
|
extern void SPI_cursor_close(Portal portal);
|
1997-08-29 11:05:57 +02:00
|
|
|
|
2003-12-02 20:26:47 +01:00
|
|
|
extern void AtEOXact_SPI(bool isCommit);
|
2004-09-16 18:58:44 +02:00
|
|
|
extern void AtEOSubXact_SPI(bool isCommit, SubTransactionId mySubid);
|
2001-10-28 07:26:15 +01:00
|
|
|
|
2001-11-05 18:46:40 +01:00
|
|
|
#endif /* SPI_H */
|