2006-03-09 22:29:38 +01:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1998-08-22 14:38:39 +02:00
|
|
|
* pl_exec.c - Executor for the PL/pgSQL
|
|
|
|
* procedural language
|
|
|
|
*
|
2017-01-03 19:48:53 +01:00
|
|
|
* Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
|
2006-03-09 22:29:38 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1998-08-22 14:38:39 +02:00
|
|
|
*
|
|
|
|
*
|
2006-03-09 22:29:38 +01:00
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/pl/plpgsql/src/pl_exec.c
|
1998-08-22 14:38:39 +02:00
|
|
|
*
|
2006-03-09 22:29:38 +01:00
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2017-03-08 23:21:08 +01:00
|
|
|
#include "postgres.h"
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2002-09-05 02:43:07 +02:00
|
|
|
#include <ctype.h>
|
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2006-07-13 18:49:20 +02:00
|
|
|
#include "access/transam.h"
|
2009-08-06 22:44:32 +02:00
|
|
|
#include "access/tupconvert.h"
|
2000-07-12 04:37:39 +02:00
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_type.h"
|
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
|
|
|
#include "executor/spi.h"
|
2002-08-30 02:28:41 +02:00
|
|
|
#include "funcapi.h"
|
2009-08-04 23:22:46 +02:00
|
|
|
#include "miscadmin.h"
|
2008-08-26 00:42:34 +02:00
|
|
|
#include "nodes/nodeFuncs.h"
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
#include "optimizer/planner.h"
|
|
|
|
#include "parser/parse_coerce.h"
|
2006-09-22 23:39:58 +02:00
|
|
|
#include "parser/scansup.h"
|
2009-04-09 04:57:53 +02:00
|
|
|
#include "storage/proc.h"
|
1999-04-20 04:19:59 +02:00
|
|
|
#include "tcop/tcopprot.h"
|
2003-03-25 04:16:41 +01:00
|
|
|
#include "utils/array.h"
|
2000-07-12 04:37:39 +02:00
|
|
|
#include "utils/builtins.h"
|
2009-01-07 14:44:37 +01:00
|
|
|
#include "utils/datum.h"
|
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
|
|
|
#include "utils/fmgroids.h"
|
2000-07-12 04:37:39 +02:00
|
|
|
#include "utils/lsyscache.h"
|
2005-05-06 19:24:55 +02:00
|
|
|
#include "utils/memutils.h"
|
2011-02-23 18:18:09 +01:00
|
|
|
#include "utils/rel.h"
|
2008-03-26 19:48:59 +01:00
|
|
|
#include "utils/snapmgr.h"
|
2004-04-01 23:28:47 +02:00
|
|
|
#include "utils/typcache.h"
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2017-03-08 23:21:08 +01:00
|
|
|
#include "plpgsql.h"
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2008-04-01 05:51:09 +02:00
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
int nargs; /* number of arguments */
|
|
|
|
Oid *types; /* types of arguments */
|
|
|
|
Datum *values; /* evaluated argument values */
|
|
|
|
char *nulls; /* null markers (' '/'n' style) */
|
|
|
|
} PreparedParamsData;
|
|
|
|
|
2003-09-29 01:37:45 +02:00
|
|
|
/*
|
2007-01-28 17:15:49 +01:00
|
|
|
* All plpgsql function executions within a single transaction share the same
|
|
|
|
* executor EState for evaluating "simple" expressions. Each function call
|
|
|
|
* creates its own "eval_econtext" ExprContext within this estate for
|
|
|
|
* per-evaluation workspace. eval_econtext is freed at normal function exit,
|
|
|
|
* and the EState is freed at transaction end (in case of error, we assume
|
2014-05-06 18:12:18 +02:00
|
|
|
* that the abort mechanisms clean it all up). Furthermore, any exception
|
2009-04-09 04:57:53 +02:00
|
|
|
* block within a function has to have its own eval_econtext separate from
|
|
|
|
* the containing function's, so that we can clean up ExprContext callbacks
|
|
|
|
* properly at subtransaction exit. We maintain a stack that tracks the
|
|
|
|
* individual econtexts so that we can clean up correctly at subxact exit.
|
2007-01-28 17:15:49 +01:00
|
|
|
*
|
|
|
|
* This arrangement is a bit tedious to maintain, but it's worth the trouble
|
|
|
|
* so that we don't have to re-prepare simple expressions on each trip through
|
2014-05-06 18:12:18 +02:00
|
|
|
* a function. (We assume the case to optimize is many repetitions of a
|
2007-01-28 17:15:49 +01:00
|
|
|
* function within a transaction.)
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
*
|
|
|
|
* However, there's no value in trying to amortize simple expression setup
|
|
|
|
* across multiple executions of a DO block (inline code block), since there
|
|
|
|
* can never be any. If we use the shared EState for a DO block, the expr
|
|
|
|
* state trees are effectively leaked till end of transaction, and that can
|
|
|
|
* add up if the user keeps on submitting DO blocks. Therefore, each DO block
|
|
|
|
* has its own simple-expression EState, which is cleaned up at exit from
|
|
|
|
* plpgsql_inline_handler(). DO blocks still use the simple_econtext_stack,
|
|
|
|
* though, so that subxact abort cleanup does the right thing.
|
2003-09-29 01:37:45 +02:00
|
|
|
*/
|
2009-04-09 04:57:53 +02:00
|
|
|
typedef struct SimpleEcontextStackEntry
|
2007-01-28 17:15:49 +01:00
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
ExprContext *stack_econtext; /* a stacked econtext */
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
SubTransactionId xact_subxid; /* ID for current subxact */
|
|
|
|
struct SimpleEcontextStackEntry *next; /* next stack entry up */
|
2009-04-09 04:57:53 +02:00
|
|
|
} SimpleEcontextStackEntry;
|
2007-01-28 17:15:49 +01:00
|
|
|
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
static EState *shared_simple_eval_estate = NULL;
|
2009-04-09 04:57:53 +02:00
|
|
|
static SimpleEcontextStackEntry *simple_econtext_stack = NULL;
|
2003-09-29 01:37:45 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* Memory management within a plpgsql function generally works with three
|
|
|
|
* contexts:
|
|
|
|
*
|
|
|
|
* 1. Function-call-lifespan data, such as variable values, is kept in the
|
|
|
|
* "main" context, a/k/a the "SPI Proc" context established by SPI_connect().
|
|
|
|
* This is usually the CurrentMemoryContext while running code in this module
|
|
|
|
* (which is not good, because careless coding can easily cause
|
|
|
|
* function-lifespan memory leaks, but we live with it for now).
|
|
|
|
*
|
|
|
|
* 2. Some statement-execution routines need statement-lifespan workspace.
|
|
|
|
* A suitable context is created on-demand by get_stmt_mcontext(), and must
|
|
|
|
* be reset at the end of the requesting routine. Error recovery will clean
|
|
|
|
* it up automatically. Nested statements requiring statement-lifespan
|
|
|
|
* workspace will result in a stack of such contexts, see push_stmt_mcontext().
|
|
|
|
*
|
|
|
|
* 3. We use the eval_econtext's per-tuple memory context for expression
|
|
|
|
* evaluation, and as a general-purpose workspace for short-lived allocations.
|
|
|
|
* Such allocations usually aren't explicitly freed, but are left to be
|
|
|
|
* cleaned up by a context reset, typically done by exec_eval_cleanup().
|
|
|
|
*
|
|
|
|
* These macros are for use in making short-lived allocations:
|
|
|
|
*/
|
|
|
|
#define get_eval_mcontext(estate) \
|
|
|
|
((estate)->eval_econtext->ecxt_per_tuple_memory)
|
|
|
|
#define eval_mcontext_alloc(estate, sz) \
|
|
|
|
MemoryContextAlloc(get_eval_mcontext(estate), sz)
|
|
|
|
#define eval_mcontext_alloc0(estate, sz) \
|
|
|
|
MemoryContextAllocZero(get_eval_mcontext(estate), sz)
|
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
/*
|
|
|
|
* We use a session-wide hash table for caching cast information.
|
|
|
|
*
|
|
|
|
* Once built, the compiled expression trees (cast_expr fields) survive for
|
|
|
|
* the life of the session. At some point it might be worth invalidating
|
|
|
|
* those after pg_cast changes, but for the moment we don't bother.
|
|
|
|
*
|
|
|
|
* The evaluation state trees (cast_exprstate) are managed in the same way as
|
|
|
|
* simple expressions (i.e., we assume cast expressions are always simple).
|
2015-08-15 18:00:36 +02:00
|
|
|
*
|
|
|
|
* As with simple expressions, DO blocks don't use the shared hash table but
|
|
|
|
* must have their own. This isn't ideal, but we don't want to deal with
|
|
|
|
* multiple simple_eval_estates within a DO block.
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
*/
|
|
|
|
typedef struct /* lookup key for cast info */
|
|
|
|
{
|
|
|
|
/* NB: we assume this struct contains no padding bytes */
|
|
|
|
Oid srctype; /* source type for cast */
|
|
|
|
Oid dsttype; /* destination type for cast */
|
|
|
|
int32 srctypmod; /* source typmod for cast */
|
|
|
|
int32 dsttypmod; /* destination typmod for cast */
|
|
|
|
} plpgsql_CastHashKey;
|
|
|
|
|
|
|
|
typedef struct /* cast_hash table entry */
|
|
|
|
{
|
|
|
|
plpgsql_CastHashKey key; /* hash key --- MUST BE FIRST */
|
|
|
|
Expr *cast_expr; /* cast expression, or NULL if no-op cast */
|
Faster expression evaluation and targetlist projection.
This replaces the old, recursive tree-walk based evaluation, with
non-recursive, opcode dispatch based, expression evaluation.
Projection is now implemented as part of expression evaluation.
This both leads to significant performance improvements, and makes
future just-in-time compilation of expressions easier.
The speed gains primarily come from:
- non-recursive implementation reduces stack usage / overhead
- simple sub-expressions are implemented with a single jump, without
function calls
- sharing some state between different sub-expressions
- reduced amount of indirect/hard to predict memory accesses by laying
out operation metadata sequentially; including the avoidance of
nearly all of the previously used linked lists
- more code has been moved to expression initialization, avoiding
constant re-checks at evaluation time
Future just-in-time compilation (JIT) has become easier, as
demonstrated by released patches intended to be merged in a later
release, for primarily two reasons: Firstly, due to a stricter split
between expression initialization and evaluation, less code has to be
handled by the JIT. Secondly, due to the non-recursive nature of the
generated "instructions", less performance-critical code-paths can
easily be shared between interpreted and compiled evaluation.
The new framework allows for significant future optimizations. E.g.:
- basic infrastructure for to later reduce the per executor-startup
overhead of expression evaluation, by caching state in prepared
statements. That'd be helpful in OLTPish scenarios where
initialization overhead is measurable.
- optimizing the generated "code". A number of proposals for potential
work has already been made.
- optimizing the interpreter. Similarly a number of proposals have
been made here too.
The move of logic into the expression initialization step leads to some
backward-incompatible changes:
- Function permission checks are now done during expression
initialization, whereas previously they were done during
execution. In edge cases this can lead to errors being raised that
previously wouldn't have been, e.g. a NULL array being coerced to a
different array type previously didn't perform checks.
- The set of domain constraints to be checked, is now evaluated once
during expression initialization, previously it was re-built
every time a domain check was evaluated. For normal queries this
doesn't change much, but e.g. for plpgsql functions, which caches
ExprStates, the old set could stick around longer. The behavior
around might still change.
Author: Andres Freund, with significant changes by Tom Lane,
changes by Heikki Linnakangas
Reviewed-By: Tom Lane, Heikki Linnakangas
Discussion: https://postgr.es/m/20161206034955.bh33paeralxbtluv@alap3.anarazel.de
2017-03-14 23:45:36 +01:00
|
|
|
/* ExprState is valid only when cast_lxid matches current LXID */
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
ExprState *cast_exprstate; /* expression's eval tree */
|
|
|
|
bool cast_in_use; /* true while we're executing eval tree */
|
|
|
|
LocalTransactionId cast_lxid;
|
|
|
|
} plpgsql_CastHashEntry;
|
|
|
|
|
2015-08-15 18:00:36 +02:00
|
|
|
static MemoryContext shared_cast_context = NULL;
|
|
|
|
static HTAB *shared_cast_hash = NULL;
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/************************************************************
|
|
|
|
* Local function forward declarations
|
|
|
|
************************************************************/
|
2003-04-24 23:16:45 +02:00
|
|
|
static void plpgsql_exec_error_callback(void *arg);
|
2005-11-22 19:17:34 +01:00
|
|
|
static PLpgSQL_datum *copy_plpgsql_datum(PLpgSQL_datum *datum);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
static MemoryContext get_stmt_mcontext(PLpgSQL_execstate *estate);
|
|
|
|
static void push_stmt_mcontext(PLpgSQL_execstate *estate);
|
|
|
|
static void pop_stmt_mcontext(PLpgSQL_execstate *estate);
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-11-22 19:17:34 +01:00
|
|
|
static int exec_stmt_block(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_block *block);
|
|
|
|
static int exec_stmts(PLpgSQL_execstate *estate,
|
2005-10-15 04:49:52 +02:00
|
|
|
List *stmts);
|
2005-11-22 19:17:34 +01:00
|
|
|
static int exec_stmt(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt *stmt);
|
|
|
|
static int exec_stmt_assign(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_assign *stmt);
|
|
|
|
static int exec_stmt_perform(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_perform *stmt);
|
|
|
|
static int exec_stmt_getdiag(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_getdiag *stmt);
|
|
|
|
static int exec_stmt_if(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_if *stmt);
|
2008-05-16 00:39:49 +02:00
|
|
|
static int exec_stmt_case(PLpgSQL_execstate *estate,
|
2009-06-11 16:49:15 +02:00
|
|
|
PLpgSQL_stmt_case *stmt);
|
2005-11-22 19:17:34 +01:00
|
|
|
static int exec_stmt_loop(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_loop *stmt);
|
|
|
|
static int exec_stmt_while(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_while *stmt);
|
|
|
|
static int exec_stmt_fori(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_fori *stmt);
|
|
|
|
static int exec_stmt_fors(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_fors *stmt);
|
2008-04-07 01:43:29 +02:00
|
|
|
static int exec_stmt_forc(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_forc *stmt);
|
2011-02-16 07:52:04 +01:00
|
|
|
static int exec_stmt_foreach_a(PLpgSQL_execstate *estate,
|
2011-04-10 17:42:00 +02:00
|
|
|
PLpgSQL_stmt_foreach_a *stmt);
|
2005-11-22 19:17:34 +01:00
|
|
|
static int exec_stmt_open(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_open *stmt);
|
|
|
|
static int exec_stmt_fetch(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_fetch *stmt);
|
|
|
|
static int exec_stmt_close(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_close *stmt);
|
|
|
|
static int exec_stmt_exit(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_exit *stmt);
|
|
|
|
static int exec_stmt_return(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_return *stmt);
|
|
|
|
static int exec_stmt_return_next(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_return_next *stmt);
|
2007-07-25 06:19:09 +02:00
|
|
|
static int exec_stmt_return_query(PLpgSQL_execstate *estate,
|
2007-11-15 23:25:18 +01:00
|
|
|
PLpgSQL_stmt_return_query *stmt);
|
2005-11-22 19:17:34 +01:00
|
|
|
static int exec_stmt_raise(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_raise *stmt);
|
2015-03-26 00:05:20 +01:00
|
|
|
static int exec_stmt_assert(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_assert *stmt);
|
2005-11-22 19:17:34 +01:00
|
|
|
static int exec_stmt_execsql(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_execsql *stmt);
|
|
|
|
static int exec_stmt_dynexecute(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_dynexecute *stmt);
|
|
|
|
static int exec_stmt_dynfors(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_dynfors *stmt);
|
|
|
|
|
|
|
|
static void plpgsql_estate_setup(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_function *func,
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
ReturnSetInfo *rsi,
|
|
|
|
EState *simple_eval_estate);
|
2005-11-22 19:17:34 +01:00
|
|
|
static void exec_eval_cleanup(PLpgSQL_execstate *estate);
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2005-11-22 19:17:34 +01:00
|
|
|
static void exec_prepare_plan(PLpgSQL_execstate *estate,
|
2007-04-16 19:21:24 +02:00
|
|
|
PLpgSQL_expr *expr, int cursorOptions);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
static void exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr);
|
2017-08-15 18:28:39 +02:00
|
|
|
static void exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan);
|
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
|
|
|
static void exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno);
|
|
|
|
static bool contains_target_param(Node *node, int *target_dno);
|
2007-03-16 00:12:07 +01:00
|
|
|
static bool exec_eval_simple_expr(PLpgSQL_execstate *estate,
|
2005-11-22 19:17:34 +01:00
|
|
|
PLpgSQL_expr *expr,
|
2007-03-16 00:12:07 +01:00
|
|
|
Datum *result,
|
1999-05-25 18:15:34 +02:00
|
|
|
bool *isNull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Oid *rettype,
|
|
|
|
int32 *rettypmod);
|
1999-01-27 17:15:22 +01:00
|
|
|
|
2005-11-22 19:17:34 +01:00
|
|
|
static void exec_assign_expr(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_datum *target,
|
|
|
|
PLpgSQL_expr *expr);
|
2011-07-18 20:46:27 +02:00
|
|
|
static void exec_assign_c_string(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_datum *target,
|
|
|
|
const char *str);
|
2005-11-22 19:17:34 +01:00
|
|
|
static void exec_assign_value(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_datum *target,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Datum value, bool isNull,
|
|
|
|
Oid valtype, int32 valtypmod);
|
2005-11-22 19:17:34 +01:00
|
|
|
static void exec_eval_datum(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_datum *datum,
|
2003-08-04 02:43:34 +02:00
|
|
|
Oid *typeid,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
int32 *typetypmod,
|
2003-08-04 02:43:34 +02:00
|
|
|
Datum *value,
|
|
|
|
bool *isnull);
|
2005-11-22 19:17:34 +01:00
|
|
|
static int exec_eval_integer(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *expr,
|
2004-08-29 07:07:03 +02:00
|
|
|
bool *isNull);
|
2005-11-22 19:17:34 +01:00
|
|
|
static bool exec_eval_boolean(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *expr,
|
2004-08-29 07:07:03 +02:00
|
|
|
bool *isNull);
|
2005-11-22 19:17:34 +01:00
|
|
|
static Datum exec_eval_expr(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *expr,
|
1998-09-01 06:40:42 +02:00
|
|
|
bool *isNull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Oid *rettype,
|
|
|
|
int32 *rettypmod);
|
2005-11-22 19:17:34 +01:00
|
|
|
static int exec_run_select(PLpgSQL_execstate *estate,
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
PLpgSQL_expr *expr, long maxtuples, Portal *portalP);
|
2008-04-07 01:43:29 +02:00
|
|
|
static int exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
|
2009-06-11 16:49:15 +02:00
|
|
|
Portal portal, bool prefetch_ok);
|
2009-11-04 23:26:08 +01:00
|
|
|
static ParamListInfo setup_param_list(PLpgSQL_execstate *estate,
|
2010-02-26 03:01:40 +01:00
|
|
|
PLpgSQL_expr *expr);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
static ParamListInfo setup_unshared_param_list(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *expr);
|
2009-11-04 23:26:08 +01:00
|
|
|
static void plpgsql_param_fetch(ParamListInfo params, int paramid);
|
2005-11-22 19:17:34 +01:00
|
|
|
static void exec_move_row(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_rec *rec,
|
|
|
|
PLpgSQL_row *row,
|
1998-09-01 06:40:42 +02:00
|
|
|
HeapTuple tup, TupleDesc tupdesc);
|
2005-11-22 19:17:34 +01:00
|
|
|
static HeapTuple make_tuple_from_row(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_row *row,
|
2004-08-29 07:07:03 +02:00
|
|
|
TupleDesc tupdesc);
|
2012-12-07 05:09:52 +01:00
|
|
|
static HeapTuple get_tuple_from_datum(Datum value);
|
|
|
|
static TupleDesc get_tupdesc_from_datum(Datum value);
|
|
|
|
static void exec_move_row_from_datum(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_rec *rec,
|
|
|
|
PLpgSQL_row *row,
|
|
|
|
Datum value);
|
2012-02-12 00:06:24 +01:00
|
|
|
static char *convert_value_to_string(PLpgSQL_execstate *estate,
|
|
|
|
Datum value, Oid valtype);
|
|
|
|
static Datum exec_cast_value(PLpgSQL_execstate *estate,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
Datum value, bool *isnull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Oid valtype, int32 valtypmod,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
Oid reqtype, int32 reqtypmod);
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
static plpgsql_CastHashEntry *get_cast_hashentry(PLpgSQL_execstate *estate,
|
|
|
|
Oid srctype, int32 srctypmod,
|
|
|
|
Oid dsttype, int32 dsttypmod);
|
2005-11-22 19:17:34 +01:00
|
|
|
static void exec_init_tuple_store(PLpgSQL_execstate *estate);
|
|
|
|
static void exec_set_found(PLpgSQL_execstate *estate, bool state);
|
2007-01-28 17:15:49 +01:00
|
|
|
static void plpgsql_create_econtext(PLpgSQL_execstate *estate);
|
2009-04-09 04:57:53 +02:00
|
|
|
static void plpgsql_destroy_econtext(PLpgSQL_execstate *estate);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
static void assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var,
|
|
|
|
Datum newvalue, bool isnull, bool freeable);
|
|
|
|
static void assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var,
|
|
|
|
const char *str);
|
2008-04-01 05:51:09 +02:00
|
|
|
static PreparedParamsData *exec_eval_using_params(PLpgSQL_execstate *estate,
|
2009-06-11 16:49:15 +02:00
|
|
|
List *params);
|
2008-05-03 02:11:36 +02:00
|
|
|
static Portal exec_dynquery_with_params(PLpgSQL_execstate *estate,
|
2010-01-19 02:35:31 +01:00
|
|
|
PLpgSQL_expr *dynquery, List *params,
|
|
|
|
const char *portalname, int cursorOptions);
|
2013-10-07 21:38:49 +02:00
|
|
|
static char *format_expr_params(PLpgSQL_execstate *estate,
|
2014-05-06 18:12:18 +02:00
|
|
|
const PLpgSQL_expr *expr);
|
2013-10-07 21:38:49 +02:00
|
|
|
static char *format_preparedparamsdata(PLpgSQL_execstate *estate,
|
2014-05-06 18:12:18 +02:00
|
|
|
const PreparedParamsData *ppd);
|
2013-10-07 21:38:49 +02:00
|
|
|
|
2005-06-20 22:44:44 +02:00
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
|
|
|
* plpgsql_exec_function Called by the call handler for
|
|
|
|
* function execution.
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
*
|
|
|
|
* This is also used to execute inline code blocks (DO blocks). The only
|
|
|
|
* difference that this code is aware of is that for a DO block, we want
|
|
|
|
* to use a private simple_eval_estate, which is created and passed in by
|
|
|
|
* the caller. For regular functions, pass NULL, which implies using
|
2015-08-15 18:00:36 +02:00
|
|
|
* shared_simple_eval_estate. (When using a private simple_eval_estate,
|
|
|
|
* we must also use a private cast hashtable, but that's taken care of
|
|
|
|
* within plpgsql_estate_setup.)
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
Datum
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
plpgsql_exec_function(PLpgSQL_function *func, FunctionCallInfo fcinfo,
|
|
|
|
EState *simple_eval_estate)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
PLpgSQL_execstate estate;
|
2003-04-24 23:16:45 +02:00
|
|
|
ErrorContextCallback plerrcontext;
|
1998-09-01 06:40:42 +02:00
|
|
|
int i;
|
2005-06-22 03:35:03 +02:00
|
|
|
int rc;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-04-24 23:16:45 +02:00
|
|
|
* Setup the execution state
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
plpgsql_estate_setup(&estate, func, (ReturnSetInfo *) fcinfo->resultinfo,
|
|
|
|
simple_eval_estate);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-04-24 23:16:45 +02:00
|
|
|
* Setup error traceback support for ereport()
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2003-04-24 23:16:45 +02:00
|
|
|
plerrcontext.callback = plpgsql_exec_error_callback;
|
|
|
|
plerrcontext.arg = &estate;
|
|
|
|
plerrcontext.previous = error_context_stack;
|
|
|
|
error_context_stack = &plerrcontext;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Make local execution copies of all the datums
|
|
|
|
*/
|
2003-07-27 20:38:26 +02:00
|
|
|
estate.err_text = gettext_noop("during initialization of execution state");
|
2005-04-05 08:22:17 +02:00
|
|
|
for (i = 0; i < estate.ndatums; i++)
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-04-05 08:22:17 +02:00
|
|
|
* Store the actual call argument values into the appropriate variables
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2003-07-27 20:38:26 +02:00
|
|
|
estate.err_text = gettext_noop("while storing call arguments into local variables");
|
1998-09-01 06:40:42 +02:00
|
|
|
for (i = 0; i < func->fn_nargs; i++)
|
|
|
|
{
|
|
|
|
int n = func->fn_argvarnos[i];
|
|
|
|
|
|
|
|
switch (estate.datums[n]->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_VAR:
|
|
|
|
{
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) estate.datums[n];
|
|
|
|
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
fcinfo->arg[i],
|
|
|
|
fcinfo->argnull[i],
|
|
|
|
false);
|
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
|
|
|
|
|
|
|
/*
|
|
|
|
* Force any array-valued parameter to be stored in
|
|
|
|
* expanded form in our local variable, in hopes of
|
|
|
|
* improving efficiency of uses of the variable. (This is
|
|
|
|
* a hack, really: why only arrays? Need more thought
|
|
|
|
* about which cases are likely to win. See also
|
|
|
|
* typisarray-specific heuristic in exec_assign_value.)
|
|
|
|
*
|
|
|
|
* Special cases: If passed a R/W expanded pointer, assume
|
|
|
|
* we can commandeer the object rather than having to copy
|
|
|
|
* it. If passed a R/O expanded pointer, just keep it as
|
|
|
|
* the value of the variable for the moment. (We'll force
|
|
|
|
* it to R/W if the variable gets modified, but that may
|
|
|
|
* very well never happen.)
|
|
|
|
*/
|
|
|
|
if (!var->isnull && var->datatype->typisarray)
|
|
|
|
{
|
|
|
|
if (VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(var->value)))
|
|
|
|
{
|
|
|
|
/* take ownership of R/W object */
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
TransferExpandedObject(var->value,
|
|
|
|
CurrentMemoryContext),
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
false,
|
|
|
|
true);
|
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
|
|
|
}
|
|
|
|
else if (VARATT_IS_EXTERNAL_EXPANDED_RO(DatumGetPointer(var->value)))
|
|
|
|
{
|
|
|
|
/* R/O pointer, keep it as-is until assigned to */
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* flat array, so force to expanded form */
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
expand_array(var->value,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
CurrentMemoryContext,
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
NULL),
|
|
|
|
false,
|
|
|
|
true);
|
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
|
|
|
}
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_ROW:
|
|
|
|
{
|
2000-05-28 19:56:29 +02:00
|
|
|
PLpgSQL_row *row = (PLpgSQL_row *) estate.datums[n];
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2004-02-24 02:44:33 +01:00
|
|
|
if (!fcinfo->argnull[i])
|
|
|
|
{
|
2012-12-07 05:09:52 +01:00
|
|
|
/* Assign row value from composite datum */
|
|
|
|
exec_move_row_from_datum(&estate, NULL, row,
|
|
|
|
fcinfo->arg[i]);
|
2004-02-24 02:44:33 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If arg is null, treat it as an empty row */
|
|
|
|
exec_move_row(&estate, NULL, row, NULL, NULL);
|
|
|
|
}
|
2012-02-12 00:06:24 +01:00
|
|
|
/* clean up after exec_move_row() */
|
|
|
|
exec_eval_cleanup(&estate);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized dtype: %d", func->datums[i]->dtype);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate.err_text = gettext_noop("during function entry");
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Set the magic variable FOUND to false
|
|
|
|
*/
|
|
|
|
exec_set_found(&estate, false);
|
|
|
|
|
2006-08-15 21:01:17 +02:00
|
|
|
/*
|
|
|
|
* Let the instrumentation plugin peek at this function
|
|
|
|
*/
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
|
|
|
|
((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
|
2006-08-15 21:01:17 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Now call the toplevel block of statements
|
|
|
|
*/
|
2003-04-24 23:16:45 +02:00
|
|
|
estate.err_text = NULL;
|
|
|
|
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
|
2005-06-22 03:35:03 +02:00
|
|
|
rc = exec_stmt_block(&estate, func->action);
|
|
|
|
if (rc != PLPGSQL_RC_RETURN)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2003-04-24 23:16:45 +02:00
|
|
|
estate.err_stmt = NULL;
|
2003-07-27 20:38:26 +02:00
|
|
|
estate.err_text = NULL;
|
2015-08-22 02:17:19 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
|
|
|
|
errmsg("control reached end of function without RETURN")));
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* We got a return value - process it
|
|
|
|
*/
|
2003-04-24 23:16:45 +02:00
|
|
|
estate.err_stmt = NULL;
|
2003-07-27 20:38:26 +02:00
|
|
|
estate.err_text = gettext_noop("while casting return value to function's return type");
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2000-05-28 19:56:29 +02:00
|
|
|
fcinfo->isnull = estate.retisnull;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2002-08-30 02:28:41 +02:00
|
|
|
if (estate.retisset)
|
|
|
|
{
|
|
|
|
ReturnSetInfo *rsi = estate.rsi;
|
|
|
|
|
|
|
|
/* Check caller can handle a set result */
|
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
2002-08-30 02:28:41 +02:00
|
|
|
rsi->returnMode = SFRM_Materialize;
|
|
|
|
|
|
|
|
/* If we produced any tuples, send back the result */
|
|
|
|
if (estate.tuple_store)
|
|
|
|
{
|
|
|
|
rsi->setResult = estate.tuple_store;
|
|
|
|
if (estate.rettupdesc)
|
2003-03-09 03:19:13 +01:00
|
|
|
{
|
|
|
|
MemoryContext oldcxt;
|
|
|
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(estate.tuple_store_cxt);
|
2002-08-30 02:28:41 +02:00
|
|
|
rsi->setDesc = CreateTupleDescCopy(estate.rettupdesc);
|
2003-03-09 03:19:13 +01:00
|
|
|
MemoryContextSwitchTo(oldcxt);
|
|
|
|
}
|
2002-08-30 02:28:41 +02:00
|
|
|
}
|
|
|
|
estate.retval = (Datum) 0;
|
|
|
|
fcinfo->isnull = true;
|
|
|
|
}
|
|
|
|
else if (!estate.retisnull)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2001-11-05 20:41:56 +01:00
|
|
|
if (estate.retistuple)
|
|
|
|
{
|
2006-01-03 23:48:10 +01:00
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* We have to check that the returned tuple actually matches the
|
|
|
|
* expected result type. XXX would be better to cache the tupdesc
|
|
|
|
* instead of repeating get_call_result_type()
|
2006-01-03 23:48:10 +01:00
|
|
|
*/
|
2009-08-06 22:44:32 +02:00
|
|
|
HeapTuple rettup = (HeapTuple) DatumGetPointer(estate.retval);
|
2006-01-03 23:48:10 +01:00
|
|
|
TupleDesc tupdesc;
|
2009-08-06 22:44:32 +02:00
|
|
|
TupleConversionMap *tupmap;
|
2006-01-03 23:48:10 +01:00
|
|
|
|
|
|
|
switch (get_call_result_type(fcinfo, NULL, &tupdesc))
|
|
|
|
{
|
|
|
|
case TYPEFUNC_COMPOSITE:
|
|
|
|
/* got the expected result rowtype, now check it */
|
2009-08-06 22:44:32 +02:00
|
|
|
tupmap = convert_tuples_by_position(estate.rettupdesc,
|
|
|
|
tupdesc,
|
|
|
|
gettext_noop("returned record type does not match expected record type"));
|
|
|
|
/* it might need conversion */
|
|
|
|
if (tupmap)
|
|
|
|
rettup = do_convert_tuple(rettup, tupmap);
|
|
|
|
/* no need to free map, we're about to return anyway */
|
2006-01-03 23:48:10 +01:00
|
|
|
break;
|
|
|
|
case TYPEFUNC_RECORD:
|
2006-10-04 02:30:14 +02:00
|
|
|
|
2006-01-03 23:48:10 +01:00
|
|
|
/*
|
|
|
|
* Failed to determine actual type of RECORD. We could
|
2006-10-04 02:30:14 +02:00
|
|
|
* raise an error here, but what this means in practice is
|
|
|
|
* that the caller is expecting any old generic rowtype,
|
|
|
|
* so we don't really need to be restrictive. Pass back
|
|
|
|
* the generated result type, instead.
|
2006-01-03 23:48:10 +01:00
|
|
|
*/
|
|
|
|
tupdesc = estate.rettupdesc;
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
if (tupdesc == NULL) /* shouldn't happen */
|
2006-01-03 23:48:10 +01:00
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* shouldn't get here if retistuple is true ... */
|
|
|
|
elog(ERROR, "return type must be a row type");
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Copy tuple to upper executor memory, as a tuple Datum. Make
|
|
|
|
* sure it is labeled with the caller-supplied tuple type.
|
2006-01-03 23:48:10 +01:00
|
|
|
*/
|
2009-08-06 22:44:32 +02:00
|
|
|
estate.retval = PointerGetDatum(SPI_returntuple(rettup, tupdesc));
|
2001-11-05 20:41:56 +01:00
|
|
|
}
|
|
|
|
else
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2001-11-05 20:41:56 +01:00
|
|
|
/* Cast value to proper type */
|
2012-02-12 00:06:24 +01:00
|
|
|
estate.retval = exec_cast_value(&estate,
|
|
|
|
estate.retval,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
&fcinfo->isnull,
|
2012-02-12 00:06:24 +01:00
|
|
|
estate.rettype,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
-1,
|
2001-11-05 20:41:56 +01:00
|
|
|
func->fn_rettype,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
-1);
|
2001-11-08 21:37:52 +01:00
|
|
|
|
2001-11-05 20:41:56 +01:00
|
|
|
/*
|
2004-11-30 04:50:29 +01:00
|
|
|
* If the function's return type isn't by value, copy the value
|
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
|
|
|
* into upper executor memory context. However, if we have a R/W
|
|
|
|
* expanded datum, we can just transfer its ownership out to the
|
|
|
|
* upper executor context.
|
2001-11-05 20:41:56 +01:00
|
|
|
*/
|
|
|
|
if (!fcinfo->isnull && !func->fn_retbyval)
|
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
|
|
|
estate.retval = SPI_datumTransfer(estate.retval,
|
|
|
|
false,
|
|
|
|
func->fn_rettyplen);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate.err_text = gettext_noop("during function exit");
|
|
|
|
|
2006-08-15 21:01:17 +02:00
|
|
|
/*
|
|
|
|
* Let the instrumentation plugin peek at this function
|
|
|
|
*/
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
|
|
|
|
((*plpgsql_plugin_ptr)->func_end) (&estate, func);
|
2006-08-15 21:01:17 +02:00
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
/* Clean up any leftover temporary memory */
|
2009-04-09 04:57:53 +02:00
|
|
|
plpgsql_destroy_econtext(&estate);
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(&estate);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* stmt_mcontext will be destroyed when function's main context is */
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-04-24 23:16:45 +02:00
|
|
|
* Pop the error context stack
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
2003-04-24 23:16:45 +02:00
|
|
|
error_context_stack = plerrcontext.previous;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2004-11-30 04:50:29 +01:00
|
|
|
* Return the function's result
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
return estate.retval;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* plpgsql_exec_trigger Called by the call handler for
|
|
|
|
* trigger execution.
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
HeapTuple
|
2005-11-22 19:17:34 +01:00
|
|
|
plpgsql_exec_trigger(PLpgSQL_function *func,
|
1998-09-01 06:40:42 +02:00
|
|
|
TriggerData *trigdata)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
PLpgSQL_execstate estate;
|
2003-04-24 23:16:45 +02:00
|
|
|
ErrorContextCallback plerrcontext;
|
1998-09-01 06:40:42 +02:00
|
|
|
int i;
|
2005-06-22 03:35:03 +02:00
|
|
|
int rc;
|
1998-09-01 06:40:42 +02:00
|
|
|
PLpgSQL_var *var;
|
2002-11-23 04:59:09 +01:00
|
|
|
PLpgSQL_rec *rec_new,
|
2003-08-04 02:43:34 +02:00
|
|
|
*rec_old;
|
1998-09-01 06:40:42 +02:00
|
|
|
HeapTuple rettup;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-04-24 23:16:45 +02:00
|
|
|
* Setup the execution state
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
plpgsql_estate_setup(&estate, func, NULL, NULL);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-04-24 23:16:45 +02:00
|
|
|
* Setup error traceback support for ereport()
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2003-04-24 23:16:45 +02:00
|
|
|
plerrcontext.callback = plpgsql_exec_error_callback;
|
|
|
|
plerrcontext.arg = &estate;
|
|
|
|
plerrcontext.previous = error_context_stack;
|
|
|
|
error_context_stack = &plerrcontext;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Make local execution copies of all the datums
|
|
|
|
*/
|
2003-07-27 20:38:26 +02:00
|
|
|
estate.err_text = gettext_noop("during initialization of execution state");
|
2005-04-05 08:22:17 +02:00
|
|
|
for (i = 0; i < estate.ndatums; i++)
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-11-23 04:59:09 +01:00
|
|
|
* Put the OLD and NEW tuples into record variables
|
2009-11-04 23:26:08 +01:00
|
|
|
*
|
2010-02-26 03:01:40 +01:00
|
|
|
* We make the tupdescs available in both records even though only one may
|
|
|
|
* have a value. This allows parsing of record references to succeed in
|
2014-05-06 18:12:18 +02:00
|
|
|
* functions that are used for multiple trigger types. For example, we
|
2010-02-26 03:01:40 +01:00
|
|
|
* might have a test like "if (TG_OP = 'INSERT' and NEW.foo = 'xyz')",
|
2009-11-04 23:26:08 +01:00
|
|
|
* which should parse regardless of the current trigger type.
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
rec_new = (PLpgSQL_rec *) (estate.datums[func->new_varno]);
|
2001-08-02 23:31:23 +02:00
|
|
|
rec_new->freetup = false;
|
2009-11-04 23:26:08 +01:00
|
|
|
rec_new->tupdesc = trigdata->tg_relation->rd_att;
|
2001-08-02 23:31:23 +02:00
|
|
|
rec_new->freetupdesc = false;
|
1998-09-01 06:40:42 +02:00
|
|
|
rec_old = (PLpgSQL_rec *) (estate.datums[func->old_varno]);
|
2001-08-02 23:31:23 +02:00
|
|
|
rec_old->freetup = false;
|
2009-11-04 23:26:08 +01:00
|
|
|
rec_old->tupdesc = trigdata->tg_relation->rd_att;
|
2001-08-02 23:31:23 +02:00
|
|
|
rec_old->freetupdesc = false;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2010-10-08 19:27:31 +02:00
|
|
|
if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
2002-11-23 04:59:09 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Per-statement triggers don't use OLD/NEW variables
|
|
|
|
*/
|
|
|
|
rec_new->tup = NULL;
|
|
|
|
rec_old->tup = NULL;
|
|
|
|
}
|
|
|
|
else if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
|
|
|
rec_new->tup = trigdata->tg_trigtuple;
|
|
|
|
rec_old->tup = NULL;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
|
|
|
{
|
|
|
|
rec_new->tup = trigdata->tg_newtuple;
|
|
|
|
rec_old->tup = trigdata->tg_trigtuple;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
|
|
|
|
{
|
|
|
|
rec_new->tup = NULL;
|
|
|
|
rec_old->tup = trigdata->tg_trigtuple;
|
|
|
|
}
|
|
|
|
else
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, or UPDATE");
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2017-04-05 01:36:39 +02:00
|
|
|
/* Make transition tables visible to this SPI connection */
|
|
|
|
rc = SPI_register_trigger_data(trigdata);
|
|
|
|
Assert(rc >= 0);
|
2017-04-01 06:30:08 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2002-11-23 04:59:09 +01:00
|
|
|
* Assign the special tg_ variables
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2002-11-23 04:59:09 +01:00
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_op_varno]);
|
|
|
|
if (TRIGGER_FIRED_BY_INSERT(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "INSERT");
|
2002-11-23 04:59:09 +01:00
|
|
|
else if (TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "UPDATE");
|
2002-11-23 04:59:09 +01:00
|
|
|
else if (TRIGGER_FIRED_BY_DELETE(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "DELETE");
|
2008-03-28 01:21:56 +01:00
|
|
|
else if (TRIGGER_FIRED_BY_TRUNCATE(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "TRUNCATE");
|
2002-11-23 04:59:09 +01:00
|
|
|
else
|
2008-03-28 01:21:56 +01:00
|
|
|
elog(ERROR, "unrecognized trigger action: not INSERT, DELETE, UPDATE, or TRUNCATE");
|
2005-03-25 02:45:42 +01:00
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_name_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
DirectFunctionCall1(namein,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
CStringGetDatum(trigdata->tg_trigger->tgname)),
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
false, true);
|
2005-03-25 02:45:42 +01:00
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_when_varno]);
|
1998-09-01 06:40:42 +02:00
|
|
|
if (TRIGGER_FIRED_BEFORE(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "BEFORE");
|
1998-09-01 06:40:42 +02:00
|
|
|
else if (TRIGGER_FIRED_AFTER(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "AFTER");
|
2010-10-10 19:43:33 +02:00
|
|
|
else if (TRIGGER_FIRED_INSTEAD(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "INSTEAD OF");
|
1998-09-01 06:40:42 +02:00
|
|
|
else
|
2010-10-10 19:43:33 +02:00
|
|
|
elog(ERROR, "unrecognized trigger execution time: not BEFORE, AFTER, or INSTEAD OF");
|
2005-03-25 02:45:42 +01:00
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_level_varno]);
|
1998-09-01 06:40:42 +02:00
|
|
|
if (TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "ROW");
|
1998-09-01 06:40:42 +02:00
|
|
|
else if (TRIGGER_FIRED_FOR_STATEMENT(trigdata->tg_event))
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, "STATEMENT");
|
1998-09-01 06:40:42 +02:00
|
|
|
else
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized trigger event type: not ROW or STATEMENT");
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_relid_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
ObjectIdGetDatum(trigdata->tg_relation->rd_id),
|
|
|
|
false, false);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_relname_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
DirectFunctionCall1(namein,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
CStringGetDatum(RelationGetRelationName(trigdata->tg_relation))),
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
false, true);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2006-05-28 05:03:17 +02:00
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_table_name_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
DirectFunctionCall1(namein,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
CStringGetDatum(RelationGetRelationName(trigdata->tg_relation))),
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
false, true);
|
2006-05-28 05:03:17 +02:00
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_table_schema_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
DirectFunctionCall1(namein,
|
|
|
|
CStringGetDatum(get_namespace_name(
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
RelationGetNamespace(
|
|
|
|
trigdata->tg_relation)))),
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
false, true);
|
2006-05-28 05:03:17 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_nargs_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
Int16GetDatum(trigdata->tg_trigger->tgnargs),
|
|
|
|
false, false);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_argv_varno]);
|
|
|
|
if (trigdata->tg_trigger->tgnargs > 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* For historical reasons, tg_argv[] subscripts start at zero not one.
|
|
|
|
* So we can't use construct_array().
|
|
|
|
*/
|
|
|
|
int nelems = trigdata->tg_trigger->tgnargs;
|
|
|
|
Datum *elems;
|
|
|
|
int dims[1];
|
|
|
|
int lbs[1];
|
|
|
|
|
|
|
|
elems = palloc(sizeof(Datum) * nelems);
|
|
|
|
for (i = 0; i < nelems; i++)
|
|
|
|
elems[i] = CStringGetTextDatum(trigdata->tg_trigger->tgargs[i]);
|
|
|
|
dims[0] = nelems;
|
|
|
|
lbs[0] = 0;
|
|
|
|
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var,
|
|
|
|
PointerGetDatum(construct_md_array(elems, NULL,
|
|
|
|
1, dims, lbs,
|
|
|
|
TEXTOID,
|
|
|
|
-1, false, 'i')),
|
|
|
|
false, true);
|
2009-11-04 23:26:08 +01:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
else
|
|
|
|
{
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(&estate, var, (Datum) 0, true, false);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate.err_text = gettext_noop("during function entry");
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Set the magic variable FOUND to false
|
|
|
|
*/
|
|
|
|
exec_set_found(&estate, false);
|
|
|
|
|
2006-08-15 21:01:17 +02:00
|
|
|
/*
|
|
|
|
* Let the instrumentation plugin peek at this function
|
|
|
|
*/
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
|
|
|
|
((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
|
2006-08-15 21:01:17 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Now call the toplevel block of statements
|
|
|
|
*/
|
2003-04-24 23:16:45 +02:00
|
|
|
estate.err_text = NULL;
|
|
|
|
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
|
2005-06-22 03:35:03 +02:00
|
|
|
rc = exec_stmt_block(&estate, func->action);
|
|
|
|
if (rc != PLPGSQL_RC_RETURN)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2003-04-24 23:16:45 +02:00
|
|
|
estate.err_stmt = NULL;
|
2003-07-27 20:38:26 +02:00
|
|
|
estate.err_text = NULL;
|
2015-08-22 02:17:19 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("control reached end of trigger procedure without RETURN")));
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate.err_stmt = NULL;
|
|
|
|
estate.err_text = gettext_noop("during function exit");
|
|
|
|
|
2002-08-30 02:28:41 +02:00
|
|
|
if (estate.retisset)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("trigger procedure cannot return a set")));
|
2002-08-30 02:28:41 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Check that the returned tuple structure has the same attributes, the
|
|
|
|
* relation that fired the trigger has. A per-statement trigger always
|
|
|
|
* needs to return NULL, so we ignore any return value the function itself
|
|
|
|
* produces (XXX: is this a good idea?)
|
1998-09-01 06:40:42 +02:00
|
|
|
*
|
2001-03-22 07:16:21 +01:00
|
|
|
* XXX This way it is possible, that the trigger returns a tuple where
|
2005-10-15 04:49:52 +02:00
|
|
|
* attributes don't have the correct atttypmod's length. It's up to the
|
|
|
|
* trigger's programmer to ensure that this doesn't happen. Jan
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2010-10-08 19:27:31 +02:00
|
|
|
if (estate.retisnull || !TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
|
1998-09-01 06:40:42 +02:00
|
|
|
rettup = NULL;
|
|
|
|
else
|
|
|
|
{
|
2009-08-06 22:44:32 +02:00
|
|
|
TupleConversionMap *tupmap;
|
|
|
|
|
|
|
|
rettup = (HeapTuple) DatumGetPointer(estate.retval);
|
|
|
|
/* check rowtype compatibility */
|
|
|
|
tupmap = convert_tuples_by_position(estate.rettupdesc,
|
|
|
|
trigdata->tg_relation->rd_att,
|
|
|
|
gettext_noop("returned row structure does not match the structure of the triggering table"));
|
|
|
|
/* it might need conversion */
|
|
|
|
if (tupmap)
|
|
|
|
rettup = do_convert_tuple(rettup, tupmap);
|
|
|
|
/* no need to free map, we're about to return anyway */
|
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
/* Copy tuple to upper executor memory */
|
2009-08-06 22:44:32 +02:00
|
|
|
rettup = SPI_copytuple(rettup);
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2006-08-15 21:01:17 +02:00
|
|
|
/*
|
|
|
|
* Let the instrumentation plugin peek at this function
|
|
|
|
*/
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
|
|
|
|
((*plpgsql_plugin_ptr)->func_end) (&estate, func);
|
2006-08-15 21:01:17 +02:00
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
/* Clean up any leftover temporary memory */
|
2009-04-09 04:57:53 +02:00
|
|
|
plpgsql_destroy_econtext(&estate);
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(&estate);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* stmt_mcontext will be destroyed when function's main context is */
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-04-24 23:16:45 +02:00
|
|
|
* Pop the error context stack
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2003-04-24 23:16:45 +02:00
|
|
|
error_context_stack = plerrcontext.previous;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-06-14 08:43:15 +02:00
|
|
|
* Return the trigger's result
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
return rettup;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* ----------
|
|
|
|
* plpgsql_exec_event_trigger Called by the call handler for
|
|
|
|
* event trigger execution.
|
|
|
|
* ----------
|
|
|
|
*/
|
2012-07-20 17:38:47 +02:00
|
|
|
void
|
|
|
|
plpgsql_exec_event_trigger(PLpgSQL_function *func, EventTriggerData *trigdata)
|
|
|
|
{
|
|
|
|
PLpgSQL_execstate estate;
|
|
|
|
ErrorContextCallback plerrcontext;
|
|
|
|
int i;
|
|
|
|
int rc;
|
|
|
|
PLpgSQL_var *var;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup the execution state
|
|
|
|
*/
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
plpgsql_estate_setup(&estate, func, NULL, NULL);
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup error traceback support for ereport()
|
|
|
|
*/
|
|
|
|
plerrcontext.callback = plpgsql_exec_error_callback;
|
|
|
|
plerrcontext.arg = &estate;
|
|
|
|
plerrcontext.previous = error_context_stack;
|
|
|
|
error_context_stack = &plerrcontext;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Make local execution copies of all the datums
|
|
|
|
*/
|
|
|
|
estate.err_text = gettext_noop("during initialization of execution state");
|
|
|
|
for (i = 0; i < estate.ndatums; i++)
|
|
|
|
estate.datums[i] = copy_plpgsql_datum(func->datums[i]);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Assign the special tg_ variables
|
|
|
|
*/
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_event_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, trigdata->event);
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate.datums[func->tg_tag_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(&estate, var, trigdata->tag);
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Let the instrumentation plugin peek at this function
|
|
|
|
*/
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_beg)
|
|
|
|
((*plpgsql_plugin_ptr)->func_beg) (&estate, func);
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now call the toplevel block of statements
|
|
|
|
*/
|
|
|
|
estate.err_text = NULL;
|
|
|
|
estate.err_stmt = (PLpgSQL_stmt *) (func->action);
|
|
|
|
rc = exec_stmt_block(&estate, func->action);
|
|
|
|
if (rc != PLPGSQL_RC_RETURN)
|
|
|
|
{
|
|
|
|
estate.err_stmt = NULL;
|
|
|
|
estate.err_text = NULL;
|
2015-08-22 02:17:19 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_S_R_E_FUNCTION_EXECUTED_NO_RETURN_STATEMENT),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("control reached end of trigger procedure without RETURN")));
|
2012-07-20 17:38:47 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
estate.err_stmt = NULL;
|
|
|
|
estate.err_text = gettext_noop("during function exit");
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let the instrumentation plugin peek at this function
|
|
|
|
*/
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->func_end)
|
|
|
|
((*plpgsql_plugin_ptr)->func_end) (&estate, func);
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
/* Clean up any leftover temporary memory */
|
|
|
|
plpgsql_destroy_econtext(&estate);
|
|
|
|
exec_eval_cleanup(&estate);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* stmt_mcontext will be destroyed when function's main context is */
|
2012-07-20 17:38:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Pop the error context stack
|
|
|
|
*/
|
|
|
|
error_context_stack = plerrcontext.previous;
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2003-04-24 23:16:45 +02:00
|
|
|
/*
|
|
|
|
* error context callback to let us supply a call-stack traceback
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
plpgsql_exec_error_callback(void *arg)
|
|
|
|
{
|
|
|
|
PLpgSQL_execstate *estate = (PLpgSQL_execstate *) arg;
|
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
if (estate->err_text != NULL)
|
2003-07-27 20:38:26 +02:00
|
|
|
{
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We don't expend the cycles to run gettext() on err_text unless we
|
|
|
|
* actually need it. Therefore, places that set up err_text should
|
|
|
|
* use gettext_noop() to ensure the strings get recorded in the
|
|
|
|
* message dictionary.
|
2007-01-28 18:58:13 +01:00
|
|
|
*
|
|
|
|
* If both err_text and err_stmt are set, use the err_text as
|
2007-11-15 22:14:46 +01:00
|
|
|
* description, but report the err_stmt's line number. When err_stmt
|
|
|
|
* is not set, we're in function entry/exit, or some such place not
|
|
|
|
* attached to a specific line number.
|
2003-08-04 02:43:34 +02:00
|
|
|
*/
|
2007-01-28 18:58:13 +01:00
|
|
|
if (estate->err_stmt != NULL)
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
/*
|
|
|
|
* translator: last %s is a phrase such as "during statement block
|
|
|
|
* local variable initialization"
|
|
|
|
*/
|
2012-02-01 08:14:37 +01:00
|
|
|
errcontext("PL/pgSQL function %s line %d %s",
|
2012-01-31 09:34:50 +01:00
|
|
|
estate->func->fn_signature,
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_stmt->lineno,
|
2009-02-18 12:33:04 +01:00
|
|
|
_(estate->err_text));
|
2007-01-28 18:58:13 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
/*
|
|
|
|
* translator: last %s is a phrase such as "while storing call
|
|
|
|
* arguments into local variables"
|
|
|
|
*/
|
2012-02-01 08:14:37 +01:00
|
|
|
errcontext("PL/pgSQL function %s %s",
|
2012-01-31 09:34:50 +01:00
|
|
|
estate->func->fn_signature,
|
2009-02-18 12:33:04 +01:00
|
|
|
_(estate->err_text));
|
2007-01-28 18:58:13 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (estate->err_stmt != NULL)
|
|
|
|
{
|
|
|
|
/* translator: last %s is a plpgsql statement type name */
|
2012-02-01 08:14:37 +01:00
|
|
|
errcontext("PL/pgSQL function %s line %d at %s",
|
2012-01-31 09:34:50 +01:00
|
|
|
estate->func->fn_signature,
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_stmt->lineno,
|
|
|
|
plpgsql_stmt_typename(estate->err_stmt));
|
2003-07-27 20:38:26 +02:00
|
|
|
}
|
2003-04-24 23:16:45 +02:00
|
|
|
else
|
2012-02-01 08:14:37 +01:00
|
|
|
errcontext("PL/pgSQL function %s",
|
2012-01-31 09:34:50 +01:00
|
|
|
estate->func->fn_signature);
|
2003-04-24 23:16:45 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
2005-04-05 08:22:17 +02:00
|
|
|
* Support function for initializing local execution variables
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
static PLpgSQL_datum *
|
2005-11-22 19:17:34 +01:00
|
|
|
copy_plpgsql_datum(PLpgSQL_datum *datum)
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
{
|
2005-04-05 08:22:17 +02:00
|
|
|
PLpgSQL_datum *result;
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
|
|
|
|
switch (datum->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_VAR:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_var *new = palloc(sizeof(PLpgSQL_var));
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
memcpy(new, datum, sizeof(PLpgSQL_var));
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/* should be preset to null/non-freeable */
|
|
|
|
Assert(new->isnull);
|
|
|
|
Assert(!new->freeval);
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
result = (PLpgSQL_datum *) new;
|
|
|
|
}
|
|
|
|
break;
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_REC:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_rec *new = palloc(sizeof(PLpgSQL_rec));
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
memcpy(new, datum, sizeof(PLpgSQL_rec));
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/* should be preset to null/non-freeable */
|
|
|
|
Assert(new->tup == NULL);
|
|
|
|
Assert(new->tupdesc == NULL);
|
|
|
|
Assert(!new->freetup);
|
|
|
|
Assert(!new->freetupdesc);
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
result = (PLpgSQL_datum *) new;
|
|
|
|
}
|
|
|
|
break;
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_ROW:
|
|
|
|
case PLPGSQL_DTYPE_RECFIELD:
|
|
|
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
2006-05-30 15:40:56 +02:00
|
|
|
|
2005-04-05 08:22:17 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* These datum records are read-only at runtime, so no need to
|
2012-06-10 21:20:04 +02:00
|
|
|
* copy them (well, ARRAYELEM contains some cached type data, but
|
|
|
|
* we'd just as soon centralize the caching anyway)
|
2005-04-05 08:22:17 +02:00
|
|
|
*/
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
result = datum;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized dtype: %d", datum->dtype);
|
2005-04-05 08:22:17 +02:00
|
|
|
result = NULL; /* keep compiler quiet */
|
|
|
|
break;
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* Create a memory context for statement-lifespan variables, if we don't
|
|
|
|
* have one already. It will be a child of stmt_mcontext_parent, which is
|
|
|
|
* either the function's main context or a pushed-down outer stmt_mcontext.
|
|
|
|
*/
|
|
|
|
static MemoryContext
|
|
|
|
get_stmt_mcontext(PLpgSQL_execstate *estate)
|
|
|
|
{
|
|
|
|
if (estate->stmt_mcontext == NULL)
|
|
|
|
{
|
|
|
|
estate->stmt_mcontext =
|
|
|
|
AllocSetContextCreate(estate->stmt_mcontext_parent,
|
|
|
|
"PLpgSQL per-statement data",
|
Add macros to make AllocSetContextCreate() calls simpler and safer.
I found that half a dozen (nearly 5%) of our AllocSetContextCreate calls
had typos in the context-sizing parameters. While none of these led to
especially significant problems, they did create minor inefficiencies,
and it's now clear that expecting people to copy-and-paste those calls
accurately is not a great idea. Let's reduce the risk of future errors
by introducing single macros that encapsulate the common use-cases.
Three such macros are enough to cover all but two special-purpose contexts;
those two calls can be left as-is, I think.
While this patch doesn't in itself improve matters for third-party
extensions, it doesn't break anything for them either, and they can
gradually adopt the simplified notation over time.
In passing, change TopMemoryContext to use the default allocation
parameters. Formerly it could only be extended 8K at a time. That was
probably reasonable when this code was written; but nowadays we create
many more contexts than we did then, so that it's not unusual to have a
couple hundred K in TopMemoryContext, even without considering various
dubious code that sticks other things there. There seems no good reason
not to let it use growing blocks like most other contexts.
Back-patch to 9.6, mostly because that's still close enough to HEAD that
it's easy to do so, and keeping the branches in sync can be expected to
avoid some future back-patching pain. The bugs fixed by these changes
don't seem to be significant enough to justify fixing them further back.
Discussion: <21072.1472321324@sss.pgh.pa.us>
2016-08-27 23:50:38 +02:00
|
|
|
ALLOCSET_DEFAULT_SIZES);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
}
|
|
|
|
return estate->stmt_mcontext;
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* Push down the current stmt_mcontext so that called statements won't use it.
|
|
|
|
* This is needed by statements that have statement-lifespan data and need to
|
|
|
|
* preserve it across some inner statements. The caller should eventually do
|
|
|
|
* pop_stmt_mcontext().
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
push_stmt_mcontext(PLpgSQL_execstate *estate)
|
|
|
|
{
|
|
|
|
/* Should have done get_stmt_mcontext() first */
|
|
|
|
Assert(estate->stmt_mcontext != NULL);
|
|
|
|
/* Assert we've not messed up the stack linkage */
|
|
|
|
Assert(MemoryContextGetParent(estate->stmt_mcontext) == estate->stmt_mcontext_parent);
|
|
|
|
/* Push it down to become the parent of any nested stmt mcontext */
|
|
|
|
estate->stmt_mcontext_parent = estate->stmt_mcontext;
|
|
|
|
/* And make it not available for use directly */
|
|
|
|
estate->stmt_mcontext = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Undo push_stmt_mcontext(). We assume this is done just before or after
|
|
|
|
* resetting the caller's stmt_mcontext; since that action will also delete
|
|
|
|
* any child contexts, there's no need to explicitly delete whatever context
|
|
|
|
* might currently be estate->stmt_mcontext.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
pop_stmt_mcontext(PLpgSQL_execstate *estate)
|
|
|
|
{
|
|
|
|
/* We need only pop the stack */
|
|
|
|
estate->stmt_mcontext = estate->stmt_mcontext_parent;
|
|
|
|
estate->stmt_mcontext_parent = MemoryContextGetParent(estate->stmt_mcontext);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Subroutine for exec_stmt_block: does any condition in the condition list
|
|
|
|
* match the current exception?
|
|
|
|
*/
|
2004-07-31 09:39:21 +02:00
|
|
|
static bool
|
2005-11-22 19:17:34 +01:00
|
|
|
exception_matches_conditions(ErrorData *edata, PLpgSQL_condition *cond)
|
2004-07-31 09:39:21 +02:00
|
|
|
{
|
2004-08-01 01:04:58 +02:00
|
|
|
for (; cond != NULL; cond = cond->next)
|
2004-07-31 09:39:21 +02:00
|
|
|
{
|
2004-08-21 00:00:14 +02:00
|
|
|
int sqlerrstate = cond->sqlerrstate;
|
2004-08-01 01:04:58 +02:00
|
|
|
|
|
|
|
/*
|
2015-03-26 00:05:20 +01:00
|
|
|
* OTHERS matches everything *except* query-canceled and
|
|
|
|
* assert-failure. If you're foolish enough, you can match those
|
|
|
|
* explicitly.
|
2004-08-01 01:04:58 +02:00
|
|
|
*/
|
2004-08-21 00:00:14 +02:00
|
|
|
if (sqlerrstate == 0)
|
2004-08-01 01:04:58 +02:00
|
|
|
{
|
2015-03-26 00:05:20 +01:00
|
|
|
if (edata->sqlerrcode != ERRCODE_QUERY_CANCELED &&
|
|
|
|
edata->sqlerrcode != ERRCODE_ASSERT_FAILURE)
|
2004-08-01 01:04:58 +02:00
|
|
|
return true;
|
|
|
|
}
|
2004-08-21 00:00:14 +02:00
|
|
|
/* Exact match? */
|
|
|
|
else if (edata->sqlerrcode == sqlerrstate)
|
|
|
|
return true;
|
|
|
|
/* Category match? */
|
|
|
|
else if (ERRCODE_IS_CATEGORY(sqlerrstate) &&
|
|
|
|
ERRCODE_TO_CATEGORY(edata->sqlerrcode) == sqlerrstate)
|
|
|
|
return true;
|
2004-07-31 09:39:21 +02:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
|
|
|
* exec_stmt_block Execute a block of statements
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2004-07-31 09:39:21 +02:00
|
|
|
volatile int rc = -1;
|
1998-09-01 06:40:42 +02:00
|
|
|
int i;
|
|
|
|
int n;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* First initialize all variables declared in this block
|
|
|
|
*/
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_text = gettext_noop("during statement block local variable initialization");
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
for (i = 0; i < block->n_initvars; i++)
|
|
|
|
{
|
|
|
|
n = block->initvarnos[i];
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
switch (estate->datums[n]->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_VAR:
|
|
|
|
{
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) (estate->datums[n]);
|
|
|
|
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/*
|
|
|
|
* Free any old value, in case re-entering block, and
|
|
|
|
* initialize to NULL
|
|
|
|
*/
|
|
|
|
assign_simple_var(estate, var, (Datum) 0, true, false);
|
2007-02-08 19:37:30 +01:00
|
|
|
|
|
|
|
if (var->default_val == NULL)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2007-02-08 19:37:30 +01:00
|
|
|
/*
|
|
|
|
* If needed, give the datatype a chance to reject
|
2007-11-15 22:14:46 +01:00
|
|
|
* NULLs, by assigning a NULL to the variable. We
|
|
|
|
* claim the value is of type UNKNOWN, not the var's
|
|
|
|
* datatype, else coercion will be skipped. (Do this
|
|
|
|
* before the notnull check to be consistent with
|
|
|
|
* exec_assign_value.)
|
2007-02-08 19:37:30 +01:00
|
|
|
*/
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
if (var->datatype->typtype == TYPTYPE_DOMAIN)
|
2007-02-08 19:37:30 +01:00
|
|
|
exec_assign_value(estate,
|
|
|
|
(PLpgSQL_datum *) var,
|
|
|
|
(Datum) 0,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
true,
|
2007-02-08 19:37:30 +01:00
|
|
|
UNKNOWNOID,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
-1);
|
|
|
|
|
2007-02-08 19:37:30 +01:00
|
|
|
if (var->notnull)
|
|
|
|
ereport(ERROR,
|
2005-10-15 04:49:52 +02:00
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
|
|
|
errmsg("variable \"%s\" declared NOT NULL cannot default to NULL",
|
|
|
|
var->refname)));
|
2007-02-08 19:37:30 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
exec_assign_expr(estate, (PLpgSQL_datum *) var,
|
|
|
|
var->default_val);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_REC:
|
|
|
|
{
|
|
|
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) (estate->datums[n]);
|
|
|
|
|
2001-05-21 16:22:19 +02:00
|
|
|
if (rec->freetup)
|
|
|
|
{
|
|
|
|
heap_freetuple(rec->tup);
|
|
|
|
rec->freetup = false;
|
|
|
|
}
|
2009-11-04 23:26:08 +01:00
|
|
|
if (rec->freetupdesc)
|
|
|
|
{
|
|
|
|
FreeTupleDesc(rec->tupdesc);
|
|
|
|
rec->freetupdesc = false;
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
rec->tup = NULL;
|
|
|
|
rec->tupdesc = NULL;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_RECFIELD:
|
2003-03-25 04:16:41 +01:00
|
|
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
1998-09-01 06:40:42 +02:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized dtype: %d",
|
|
|
|
estate->datums[n]->dtype);
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2004-07-31 09:39:21 +02:00
|
|
|
if (block->exceptions)
|
|
|
|
{
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Execute the statements in the block's body inside a sub-transaction
|
2004-07-31 09:39:21 +02:00
|
|
|
*/
|
2004-08-29 07:07:03 +02:00
|
|
|
MemoryContext oldcontext = CurrentMemoryContext;
|
2004-09-13 22:10:13 +02:00
|
|
|
ResourceOwner oldowner = CurrentResourceOwner;
|
2007-01-28 17:15:49 +01:00
|
|
|
ExprContext *old_eval_econtext = estate->eval_econtext;
|
2011-04-10 17:42:00 +02:00
|
|
|
ErrorData *save_cur_error = estate->cur_error;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext stmt_mcontext;
|
2004-07-31 09:39:21 +02:00
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_text = gettext_noop("during statement block entry");
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* We will need a stmt_mcontext to hold the error data if an error
|
|
|
|
* occurs. It seems best to force it to exist before entering the
|
|
|
|
* subtransaction, so that we reduce the risk of out-of-memory during
|
|
|
|
* error recovery, and because this greatly simplifies restoring the
|
|
|
|
* stmt_mcontext stack to the correct state after an error. We can
|
|
|
|
* ameliorate the cost of this by allowing the called statements to
|
|
|
|
* use this mcontext too; so we don't push it down here.
|
|
|
|
*/
|
|
|
|
stmt_mcontext = get_stmt_mcontext(estate);
|
|
|
|
|
2004-07-31 09:39:21 +02:00
|
|
|
BeginInternalSubTransaction(NULL);
|
|
|
|
/* Want to run statements inside function's memory context */
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2004-09-13 22:10:13 +02:00
|
|
|
|
2004-07-31 09:39:21 +02:00
|
|
|
PG_TRY();
|
2004-09-13 22:10:13 +02:00
|
|
|
{
|
2007-01-28 17:15:49 +01:00
|
|
|
/*
|
|
|
|
* We need to run the block's statements with a new eval_econtext
|
|
|
|
* that belongs to the current subtransaction; if we try to use
|
|
|
|
* the outer econtext then ExprContext shutdown callbacks will be
|
|
|
|
* called at the wrong times.
|
|
|
|
*/
|
|
|
|
plpgsql_create_econtext(estate);
|
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_text = NULL;
|
|
|
|
|
2007-01-28 17:15:49 +01:00
|
|
|
/* Run the block's statements */
|
2004-09-13 22:10:13 +02:00
|
|
|
rc = exec_stmts(estate, block->body);
|
2004-11-21 23:27:34 +01:00
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_text = gettext_noop("during statement block exit");
|
|
|
|
|
2007-04-19 18:33:24 +02:00
|
|
|
/*
|
|
|
|
* If the block ended with RETURN, we may need to copy the return
|
2007-11-15 22:14:46 +01:00
|
|
|
* value out of the subtransaction eval_context. This is
|
|
|
|
* currently only needed for scalar result types --- rowtype
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* values will always exist in the function's main memory context,
|
|
|
|
* cf. exec_stmt_return(). We can avoid a physical copy if the
|
|
|
|
* value happens to be a R/W expanded object.
|
2007-04-19 18:33:24 +02:00
|
|
|
*/
|
|
|
|
if (rc == PLPGSQL_RC_RETURN &&
|
|
|
|
!estate->retisset &&
|
|
|
|
!estate->retisnull &&
|
|
|
|
estate->rettupdesc == NULL)
|
|
|
|
{
|
|
|
|
int16 resTypLen;
|
|
|
|
bool resTypByVal;
|
|
|
|
|
|
|
|
get_typlenbyval(estate->rettype, &resTypLen, &resTypByVal);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
estate->retval = datumTransfer(estate->retval,
|
|
|
|
resTypByVal, resTypLen);
|
2007-04-19 18:33:24 +02:00
|
|
|
}
|
|
|
|
|
2004-11-21 23:27:34 +01:00
|
|
|
/* Commit the inner transaction, return to outer xact context */
|
|
|
|
ReleaseCurrentSubTransaction();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
CurrentResourceOwner = oldowner;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Assert that the stmt_mcontext stack is unchanged */
|
|
|
|
Assert(stmt_mcontext == estate->stmt_mcontext);
|
|
|
|
|
2009-04-09 04:57:53 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Revert to outer eval_econtext. (The inner one was
|
|
|
|
* automatically cleaned up during subxact exit.)
|
2009-04-09 04:57:53 +02:00
|
|
|
*/
|
2007-01-28 17:15:49 +01:00
|
|
|
estate->eval_econtext = old_eval_econtext;
|
2004-09-13 22:10:13 +02:00
|
|
|
}
|
2004-07-31 09:39:21 +02:00
|
|
|
PG_CATCH();
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
ErrorData *edata;
|
|
|
|
ListCell *e;
|
2004-07-31 09:39:21 +02:00
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_text = gettext_noop("during exception cleanup");
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Save error info in our stmt_mcontext */
|
|
|
|
MemoryContextSwitchTo(stmt_mcontext);
|
2004-07-31 09:39:21 +02:00
|
|
|
edata = CopyErrorData();
|
|
|
|
FlushErrorState();
|
|
|
|
|
2004-11-16 19:10:16 +01:00
|
|
|
/* Abort the inner transaction */
|
2004-07-31 09:39:21 +02:00
|
|
|
RollbackAndReleaseCurrentSubTransaction();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2004-09-13 22:10:13 +02:00
|
|
|
CurrentResourceOwner = oldowner;
|
2004-07-31 09:39:21 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* Set up the stmt_mcontext stack as though we had restored our
|
|
|
|
* previous state and then done push_stmt_mcontext(). The push is
|
|
|
|
* needed so that statements in the exception handler won't
|
|
|
|
* clobber the error data that's in our stmt_mcontext.
|
|
|
|
*/
|
|
|
|
estate->stmt_mcontext_parent = stmt_mcontext;
|
|
|
|
estate->stmt_mcontext = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now we can delete any nested stmt_mcontexts that might have
|
|
|
|
* been created as children of ours. (Note: we do not immediately
|
|
|
|
* release any statement-lifespan data that might have been left
|
|
|
|
* behind in stmt_mcontext itself. We could attempt that by doing
|
|
|
|
* a MemoryContextReset on it before collecting the error data
|
|
|
|
* above, but it seems too risky to do any significant amount of
|
|
|
|
* work before collecting the error.)
|
|
|
|
*/
|
|
|
|
MemoryContextDeleteChildren(stmt_mcontext);
|
|
|
|
|
2007-01-28 17:15:49 +01:00
|
|
|
/* Revert to outer eval_econtext */
|
|
|
|
estate->eval_econtext = old_eval_econtext;
|
|
|
|
|
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
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Must clean up the econtext too. However, any tuple table made
|
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
|
|
|
* in the subxact will have been thrown away by SPI during subxact
|
|
|
|
* abort, so we don't need to (and mustn't try to) free the
|
|
|
|
* eval_tuptable.
|
|
|
|
*/
|
|
|
|
estate->eval_tuptable = NULL;
|
2010-08-09 20:50:11 +02:00
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
|
2004-07-31 09:39:21 +02:00
|
|
|
/* Look for a matching exception handler */
|
2005-10-15 04:49:52 +02:00
|
|
|
foreach(e, block->exceptions->exc_list)
|
2004-07-31 09:39:21 +02:00
|
|
|
{
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
PLpgSQL_exception *exception = (PLpgSQL_exception *) lfirst(e);
|
2004-07-31 09:39:21 +02:00
|
|
|
|
2004-08-01 01:04:58 +02:00
|
|
|
if (exception_matches_conditions(edata, exception->conditions))
|
2004-07-31 09:39:21 +02:00
|
|
|
{
|
2005-06-10 18:23:11 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Initialize the magic SQLSTATE and SQLERRM variables for
|
2015-02-26 05:48:28 +01:00
|
|
|
* the exception block; this also frees values from any
|
|
|
|
* prior use of the same exception. We needn't do this
|
|
|
|
* until we have found a matching exception.
|
2005-06-10 18:23:11 +02:00
|
|
|
*/
|
|
|
|
PLpgSQL_var *state_var;
|
|
|
|
PLpgSQL_var *errm_var;
|
|
|
|
|
2005-06-20 22:44:44 +02:00
|
|
|
state_var = (PLpgSQL_var *)
|
|
|
|
estate->datums[block->exceptions->sqlstate_varno];
|
|
|
|
errm_var = (PLpgSQL_var *)
|
|
|
|
estate->datums[block->exceptions->sqlerrm_varno];
|
2008-04-07 01:43:29 +02:00
|
|
|
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(estate, state_var,
|
2008-04-07 01:43:29 +02:00
|
|
|
unpack_sql_state(edata->sqlerrcode));
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(estate, errm_var, edata->message);
|
2005-06-10 18:23:11 +02:00
|
|
|
|
2010-08-09 04:25:07 +02:00
|
|
|
/*
|
|
|
|
* Also set up cur_error so the error data is accessible
|
|
|
|
* inside the handler.
|
|
|
|
*/
|
|
|
|
estate->cur_error = edata;
|
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_text = NULL;
|
|
|
|
|
2004-07-31 09:39:21 +02:00
|
|
|
rc = exec_stmts(estate, exception->action);
|
2005-06-10 18:23:11 +02:00
|
|
|
|
2004-07-31 09:39:21 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-08-09 04:25:07 +02:00
|
|
|
/*
|
|
|
|
* Restore previous state of cur_error, whether or not we executed
|
|
|
|
* a handler. This is needed in case an error got thrown from
|
|
|
|
* some inner block's exception handler.
|
|
|
|
*/
|
|
|
|
estate->cur_error = save_cur_error;
|
|
|
|
|
2004-07-31 09:39:21 +02:00
|
|
|
/* If no match found, re-throw the error */
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
if (e == NULL)
|
2004-07-31 09:39:21 +02:00
|
|
|
ReThrowError(edata);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
|
|
|
|
/* Restore stmt_mcontext stack and release the error data */
|
|
|
|
pop_stmt_mcontext(estate);
|
|
|
|
MemoryContextReset(stmt_mcontext);
|
2004-07-31 09:39:21 +02:00
|
|
|
}
|
|
|
|
PG_END_TRY();
|
2010-08-09 04:25:07 +02:00
|
|
|
|
|
|
|
Assert(save_cur_error == estate->cur_error);
|
2004-07-31 09:39:21 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Just execute the statements in the block's body
|
|
|
|
*/
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_text = NULL;
|
|
|
|
|
2004-07-31 09:39:21 +02:00
|
|
|
rc = exec_stmts(estate, block->body);
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2007-01-28 18:58:13 +01:00
|
|
|
estate->err_text = NULL;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Handle the return code.
|
|
|
|
*/
|
|
|
|
switch (rc)
|
|
|
|
{
|
|
|
|
case PLPGSQL_RC_OK:
|
2005-06-22 03:35:03 +02:00
|
|
|
case PLPGSQL_RC_RETURN:
|
2008-05-14 00:10:30 +02:00
|
|
|
case PLPGSQL_RC_CONTINUE:
|
2005-06-22 03:35:03 +02:00
|
|
|
return rc;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
|
|
case PLPGSQL_RC_EXIT:
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2009-05-02 19:27:57 +02:00
|
|
|
/*
|
|
|
|
* This is intentionally different from the handling of RC_EXIT
|
|
|
|
* for loops: to match a block, we require a match by label.
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
if (estate->exitlabel == NULL)
|
2009-05-02 19:27:57 +02:00
|
|
|
return PLPGSQL_RC_EXIT;
|
1998-09-01 06:40:42 +02:00
|
|
|
if (block->label == NULL)
|
|
|
|
return PLPGSQL_RC_EXIT;
|
2009-05-02 19:27:57 +02:00
|
|
|
if (strcmp(block->label, estate->exitlabel) != 0)
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_EXIT;
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
return PLPGSQL_RC_OK;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
default:
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized rc: %d", rc);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmts Iterate over a list of statements
|
|
|
|
* as long as their return code is OK
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmts(PLpgSQL_execstate *estate, List *stmts)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
ListCell *s;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2005-10-24 17:10:22 +02:00
|
|
|
if (stmts == NIL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Ensure we do a CHECK_FOR_INTERRUPTS() even though there is no
|
|
|
|
* statement. This prevents hangup in a tight loop if, for instance,
|
|
|
|
* there is a LOOP construct with an empty body.
|
|
|
|
*/
|
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
foreach(s, stmts)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
PLpgSQL_stmt *stmt = (PLpgSQL_stmt *) lfirst(s);
|
2005-10-15 04:49:52 +02:00
|
|
|
int rc = exec_stmt(estate, stmt);
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
if (rc != PLPGSQL_RC_OK)
|
|
|
|
return rc;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt Distribute one statement to the statements
|
|
|
|
* type specific execution function.
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt(PLpgSQL_execstate *estate, PLpgSQL_stmt *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
PLpgSQL_stmt *save_estmt;
|
|
|
|
int rc = -1;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2003-04-24 23:16:45 +02:00
|
|
|
save_estmt = estate->err_stmt;
|
|
|
|
estate->err_stmt = stmt;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2006-08-15 21:01:17 +02:00
|
|
|
/* Let the plugin know that we are about to execute this statement */
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_beg)
|
|
|
|
((*plpgsql_plugin_ptr)->stmt_beg) (estate, stmt);
|
2006-08-15 21:01:17 +02:00
|
|
|
|
2002-08-30 02:28:41 +02:00
|
|
|
CHECK_FOR_INTERRUPTS();
|
|
|
|
|
2016-08-18 18:00:00 +02:00
|
|
|
switch (stmt->cmd_type)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
|
|
|
case PLPGSQL_STMT_BLOCK:
|
|
|
|
rc = exec_stmt_block(estate, (PLpgSQL_stmt_block *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_ASSIGN:
|
|
|
|
rc = exec_stmt_assign(estate, (PLpgSQL_stmt_assign *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2002-11-10 01:35:58 +01:00
|
|
|
case PLPGSQL_STMT_PERFORM:
|
|
|
|
rc = exec_stmt_perform(estate, (PLpgSQL_stmt_perform *) stmt);
|
|
|
|
break;
|
|
|
|
|
2000-09-05 11:02:18 +02:00
|
|
|
case PLPGSQL_STMT_GETDIAG:
|
|
|
|
rc = exec_stmt_getdiag(estate, (PLpgSQL_stmt_getdiag *) stmt);
|
|
|
|
break;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_IF:
|
|
|
|
rc = exec_stmt_if(estate, (PLpgSQL_stmt_if *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2008-05-16 00:39:49 +02:00
|
|
|
case PLPGSQL_STMT_CASE:
|
|
|
|
rc = exec_stmt_case(estate, (PLpgSQL_stmt_case *) stmt);
|
|
|
|
break;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_LOOP:
|
|
|
|
rc = exec_stmt_loop(estate, (PLpgSQL_stmt_loop *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_WHILE:
|
|
|
|
rc = exec_stmt_while(estate, (PLpgSQL_stmt_while *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_FORI:
|
|
|
|
rc = exec_stmt_fori(estate, (PLpgSQL_stmt_fori *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_FORS:
|
|
|
|
rc = exec_stmt_fors(estate, (PLpgSQL_stmt_fors *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
case PLPGSQL_STMT_FORC:
|
|
|
|
rc = exec_stmt_forc(estate, (PLpgSQL_stmt_forc *) stmt);
|
|
|
|
break;
|
|
|
|
|
2011-02-16 07:52:04 +01:00
|
|
|
case PLPGSQL_STMT_FOREACH_A:
|
|
|
|
rc = exec_stmt_foreach_a(estate, (PLpgSQL_stmt_foreach_a *) stmt);
|
|
|
|
break;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_EXIT:
|
|
|
|
rc = exec_stmt_exit(estate, (PLpgSQL_stmt_exit *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_RETURN:
|
|
|
|
rc = exec_stmt_return(estate, (PLpgSQL_stmt_return *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2002-08-30 02:28:41 +02:00
|
|
|
case PLPGSQL_STMT_RETURN_NEXT:
|
|
|
|
rc = exec_stmt_return_next(estate, (PLpgSQL_stmt_return_next *) stmt);
|
|
|
|
break;
|
|
|
|
|
2007-07-25 06:19:09 +02:00
|
|
|
case PLPGSQL_STMT_RETURN_QUERY:
|
|
|
|
rc = exec_stmt_return_query(estate, (PLpgSQL_stmt_return_query *) stmt);
|
|
|
|
break;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_RAISE:
|
|
|
|
rc = exec_stmt_raise(estate, (PLpgSQL_stmt_raise *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2015-03-26 00:05:20 +01:00
|
|
|
case PLPGSQL_STMT_ASSERT:
|
|
|
|
rc = exec_stmt_assert(estate, (PLpgSQL_stmt_assert *) stmt);
|
|
|
|
break;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_STMT_EXECSQL:
|
|
|
|
rc = exec_stmt_execsql(estate, (PLpgSQL_stmt_execsql *) stmt);
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2000-08-31 15:26:16 +02:00
|
|
|
case PLPGSQL_STMT_DYNEXECUTE:
|
|
|
|
rc = exec_stmt_dynexecute(estate, (PLpgSQL_stmt_dynexecute *) stmt);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_STMT_DYNFORS:
|
|
|
|
rc = exec_stmt_dynfors(estate, (PLpgSQL_stmt_dynfors *) stmt);
|
|
|
|
break;
|
|
|
|
|
2001-05-21 16:22:19 +02:00
|
|
|
case PLPGSQL_STMT_OPEN:
|
|
|
|
rc = exec_stmt_open(estate, (PLpgSQL_stmt_open *) stmt);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_STMT_FETCH:
|
|
|
|
rc = exec_stmt_fetch(estate, (PLpgSQL_stmt_fetch *) stmt);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_STMT_CLOSE:
|
|
|
|
rc = exec_stmt_close(estate, (PLpgSQL_stmt_close *) stmt);
|
|
|
|
break;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
default:
|
2003-04-24 23:16:45 +02:00
|
|
|
estate->err_stmt = save_estmt;
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized cmdtype: %d", stmt->cmd_type);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2006-08-15 21:01:17 +02:00
|
|
|
/* Let the plugin know that we have finished executing this statement */
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr && (*plpgsql_plugin_ptr)->stmt_end)
|
|
|
|
((*plpgsql_plugin_ptr)->stmt_end) (estate, stmt);
|
2006-08-15 21:01:17 +02:00
|
|
|
|
2003-04-24 23:16:45 +02:00
|
|
|
estate->err_stmt = save_estmt;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return rc;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_assign Evaluate an expression and
|
|
|
|
* put the result into a variable.
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_assign(PLpgSQL_execstate *estate, PLpgSQL_stmt_assign *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2002-11-10 01:35:58 +01:00
|
|
|
Assert(stmt->varno >= 0);
|
2001-05-28 21:33:24 +02:00
|
|
|
|
2002-11-10 01:35:58 +01:00
|
|
|
exec_assign_expr(estate, estate->datums[stmt->varno], stmt->expr);
|
2001-05-28 21:33:24 +02:00
|
|
|
|
2002-11-10 01:35:58 +01:00
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_perform Evaluate query and discard result (but set
|
|
|
|
* FOUND depending on whether at least one row
|
|
|
|
* was returned).
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt)
|
2002-11-10 01:35:58 +01:00
|
|
|
{
|
|
|
|
PLpgSQL_expr *expr = stmt->expr;
|
2001-05-28 21:33:24 +02:00
|
|
|
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
(void) exec_run_select(estate, expr, 0, NULL);
|
2002-11-10 01:35:58 +01:00
|
|
|
exec_set_found(estate, (estate->eval_processed != 0));
|
|
|
|
exec_eval_cleanup(estate);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2000-09-05 11:02:18 +02:00
|
|
|
/* ----------
|
2001-03-22 05:01:46 +01:00
|
|
|
* exec_stmt_getdiag Put internal PG information into
|
|
|
|
* specified variables.
|
2000-09-05 11:02:18 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_getdiag(PLpgSQL_execstate *estate, PLpgSQL_stmt_getdiag *stmt)
|
2000-09-05 11:02:18 +02:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
ListCell *lc;
|
2000-09-05 11:02:18 +02:00
|
|
|
|
2011-07-18 20:46:27 +02:00
|
|
|
/*
|
|
|
|
* GET STACKED DIAGNOSTICS is only valid inside an exception handler.
|
|
|
|
*
|
|
|
|
* Note: we trust the grammar to have disallowed the relevant item kinds
|
|
|
|
* if not is_stacked, otherwise we'd dump core below.
|
|
|
|
*/
|
|
|
|
if (stmt->is_stacked && estate->cur_error == NULL)
|
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
|
|
|
|
errmsg("GET STACKED DIAGNOSTICS cannot be used outside an exception handler")));
|
2011-07-18 20:46:27 +02:00
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
foreach(lc, stmt->diag_items)
|
2000-09-05 11:02:18 +02:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
PLpgSQL_diag_item *diag_item = (PLpgSQL_diag_item *) lfirst(lc);
|
2012-03-22 19:13:17 +01:00
|
|
|
PLpgSQL_datum *var = estate->datums[diag_item->target];
|
2001-02-19 20:49:53 +01:00
|
|
|
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
switch (diag_item->kind)
|
2000-09-05 11:02:18 +02:00
|
|
|
{
|
2001-02-19 20:49:53 +01:00
|
|
|
case PLPGSQL_GETDIAG_ROW_COUNT:
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_assign_value(estate, var,
|
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
|
|
|
UInt64GetDatum(estate->eval_processed),
|
|
|
|
false, INT8OID, -1);
|
2001-02-19 20:49:53 +01:00
|
|
|
break;
|
2000-09-05 11:02:18 +02:00
|
|
|
|
2001-02-19 20:49:53 +01:00
|
|
|
case PLPGSQL_GETDIAG_RESULT_OID:
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_assign_value(estate, var,
|
|
|
|
ObjectIdGetDatum(estate->eval_lastoid),
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
false, OIDOID, -1);
|
2001-02-19 20:49:53 +01:00
|
|
|
break;
|
2000-09-05 11:02:18 +02:00
|
|
|
|
2011-07-18 20:46:27 +02:00
|
|
|
case PLPGSQL_GETDIAG_ERROR_CONTEXT:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->context);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_GETDIAG_ERROR_DETAIL:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->detail);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_GETDIAG_ERROR_HINT:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->hint);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_GETDIAG_RETURNED_SQLSTATE:
|
|
|
|
exec_assign_c_string(estate, var,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
unpack_sql_state(estate->cur_error->sqlerrcode));
|
2011-07-18 20:46:27 +02:00
|
|
|
break;
|
|
|
|
|
2013-07-03 13:29:23 +02:00
|
|
|
case PLPGSQL_GETDIAG_COLUMN_NAME:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->column_name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_GETDIAG_CONSTRAINT_NAME:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->constraint_name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_GETDIAG_DATATYPE_NAME:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->datatype_name);
|
|
|
|
break;
|
|
|
|
|
2011-07-18 20:46:27 +02:00
|
|
|
case PLPGSQL_GETDIAG_MESSAGE_TEXT:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->message);
|
|
|
|
break;
|
|
|
|
|
2013-07-03 13:29:23 +02:00
|
|
|
case PLPGSQL_GETDIAG_TABLE_NAME:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->table_name);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_GETDIAG_SCHEMA_NAME:
|
|
|
|
exec_assign_c_string(estate, var,
|
|
|
|
estate->cur_error->schema_name);
|
|
|
|
break;
|
|
|
|
|
2013-07-25 00:53:27 +02:00
|
|
|
case PLPGSQL_GETDIAG_CONTEXT:
|
|
|
|
{
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
char *contextstackstr;
|
|
|
|
MemoryContext oldcontext;
|
2013-07-25 00:53:27 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Use eval_mcontext for short-lived string */
|
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
|
|
|
contextstackstr = GetErrorContextStack();
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2013-07-25 00:53:27 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
exec_assign_c_string(estate, var, contextstackstr);
|
2013-07-25 00:53:27 +02:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2000-09-05 11:02:18 +02:00
|
|
|
default:
|
2011-07-18 20:46:27 +02:00
|
|
|
elog(ERROR, "unrecognized diagnostic item kind: %d",
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
diag_item->kind);
|
2001-02-19 20:49:53 +01:00
|
|
|
}
|
|
|
|
}
|
2001-03-22 05:01:46 +01:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
|
2001-02-19 20:49:53 +01:00
|
|
|
return PLPGSQL_RC_OK;
|
2000-09-05 11:02:18 +02:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_if Evaluate a bool expression and
|
|
|
|
* execute the true or false body
|
|
|
|
* conditionally.
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2003-10-01 23:47:42 +02:00
|
|
|
bool value;
|
2005-06-22 03:35:03 +02:00
|
|
|
bool isnull;
|
2011-10-27 21:21:51 +02:00
|
|
|
ListCell *lc;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2003-10-01 23:47:42 +02:00
|
|
|
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(estate);
|
2003-10-01 23:47:42 +02:00
|
|
|
if (!isnull && value)
|
2011-10-27 21:21:51 +02:00
|
|
|
return exec_stmts(estate, stmt->then_body);
|
|
|
|
|
|
|
|
foreach(lc, stmt->elsif_list)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2011-10-27 21:21:51 +02:00
|
|
|
PLpgSQL_if_elsif *elif = (PLpgSQL_if_elsif *) lfirst(lc);
|
|
|
|
|
|
|
|
value = exec_eval_boolean(estate, elif->cond, &isnull);
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
if (!isnull && value)
|
|
|
|
return exec_stmts(estate, elif->stmts);
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2011-10-27 21:21:51 +02:00
|
|
|
return exec_stmts(estate, stmt->else_body);
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-05-16 00:39:49 +02:00
|
|
|
/*-----------
|
|
|
|
* exec_stmt_case
|
|
|
|
*-----------
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
|
|
|
|
{
|
|
|
|
PLpgSQL_var *t_var = NULL;
|
|
|
|
bool isnull;
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
if (stmt->t_expr != NULL)
|
|
|
|
{
|
|
|
|
/* simple case */
|
2009-06-11 16:49:15 +02:00
|
|
|
Datum t_val;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Oid t_typoid;
|
|
|
|
int32 t_typmod;
|
2008-05-16 00:39:49 +02:00
|
|
|
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
t_val = exec_eval_expr(estate, stmt->t_expr,
|
|
|
|
&isnull, &t_typoid, &t_typmod);
|
2008-05-16 00:39:49 +02:00
|
|
|
|
|
|
|
t_var = (PLpgSQL_var *) estate->datums[stmt->t_varno];
|
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* When expected datatype is different from real, change it. Note that
|
|
|
|
* what we're modifying here is an execution copy of the datum, so
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* this doesn't affect the originally stored function parse tree. (In
|
|
|
|
* theory, if the expression datatype keeps changing during execution,
|
|
|
|
* this could cause a function-lifespan memory leak. Doesn't seem
|
|
|
|
* worth worrying about though.)
|
2008-05-16 00:39:49 +02:00
|
|
|
*/
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
if (t_var->datatype->typoid != t_typoid ||
|
|
|
|
t_var->datatype->atttypmod != t_typmod)
|
|
|
|
t_var->datatype = plpgsql_build_datatype(t_typoid,
|
|
|
|
t_typmod,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
estate->func->fn_input_collation);
|
2008-05-16 00:39:49 +02:00
|
|
|
|
|
|
|
/* now we can assign to the variable */
|
|
|
|
exec_assign_value(estate,
|
|
|
|
(PLpgSQL_datum *) t_var,
|
|
|
|
t_val,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
isnull,
|
|
|
|
t_typoid,
|
|
|
|
t_typmod);
|
2008-05-16 00:39:49 +02:00
|
|
|
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Now search for a successful WHEN clause */
|
|
|
|
foreach(l, stmt->case_when_list)
|
|
|
|
{
|
|
|
|
PLpgSQL_case_when *cwt = (PLpgSQL_case_when *) lfirst(l);
|
2009-06-11 16:49:15 +02:00
|
|
|
bool value;
|
2008-05-16 00:39:49 +02:00
|
|
|
|
|
|
|
value = exec_eval_boolean(estate, cwt->expr, &isnull);
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
if (!isnull && value)
|
|
|
|
{
|
|
|
|
/* Found it */
|
|
|
|
|
|
|
|
/* We can now discard any value we had for the temp variable */
|
|
|
|
if (t_var != NULL)
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(estate, t_var, (Datum) 0, true, false);
|
2008-05-16 00:39:49 +02:00
|
|
|
|
|
|
|
/* Evaluate the statement(s), and we're done */
|
|
|
|
return exec_stmts(estate, cwt->stmts);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* We can now discard any value we had for the temp variable */
|
|
|
|
if (t_var != NULL)
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(estate, t_var, (Datum) 0, true, false);
|
2008-05-16 00:39:49 +02:00
|
|
|
|
|
|
|
/* SQL2003 mandates this error if there was no ELSE clause */
|
|
|
|
if (!stmt->have_else)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_CASE_NOT_FOUND),
|
|
|
|
errmsg("case not found"),
|
|
|
|
errhint("CASE statement is missing ELSE part.")));
|
|
|
|
|
|
|
|
/* Evaluate the ELSE statements, and we're done */
|
|
|
|
return exec_stmts(estate, stmt->else_stmts);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
|
|
|
* exec_stmt_loop Loop over statements until
|
|
|
|
* an exit occurs.
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
int rc = exec_stmts(estate, stmt->body);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
switch (rc)
|
|
|
|
{
|
|
|
|
case PLPGSQL_RC_OK:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_RC_EXIT:
|
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
if (stmt->label == NULL)
|
|
|
|
return PLPGSQL_RC_EXIT;
|
2005-06-22 03:35:03 +02:00
|
|
|
if (strcmp(stmt->label, estate->exitlabel) != 0)
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_EXIT;
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
return PLPGSQL_RC_OK;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
2005-06-22 03:35:03 +02:00
|
|
|
case PLPGSQL_RC_CONTINUE:
|
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
/* anonymous continue, so re-run the loop */
|
|
|
|
break;
|
|
|
|
else if (stmt->label != NULL &&
|
|
|
|
strcmp(stmt->label, estate->exitlabel) == 0)
|
|
|
|
/* label matches named continue, so re-run loop */
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
else
|
|
|
|
/* label doesn't match named continue, so propagate upward */
|
|
|
|
return PLPGSQL_RC_CONTINUE;
|
|
|
|
break;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
|
|
case PLPGSQL_RC_RETURN:
|
2008-05-14 00:10:30 +02:00
|
|
|
return rc;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
|
|
default:
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized rc: %d", rc);
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_while Loop over statements as long
|
|
|
|
* as an expression evaluates to
|
|
|
|
* true or an exit occurs.
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
2005-06-22 09:28:47 +02:00
|
|
|
int rc;
|
|
|
|
bool value;
|
|
|
|
bool isnull;
|
|
|
|
|
2003-10-01 23:47:42 +02:00
|
|
|
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(estate);
|
2003-10-01 23:47:42 +02:00
|
|
|
|
|
|
|
if (isnull || !value)
|
1998-09-01 06:40:42 +02:00
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
rc = exec_stmts(estate, stmt->body);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
switch (rc)
|
|
|
|
{
|
|
|
|
case PLPGSQL_RC_OK:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PLPGSQL_RC_EXIT:
|
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
if (stmt->label == NULL)
|
|
|
|
return PLPGSQL_RC_EXIT;
|
2009-05-02 19:27:57 +02:00
|
|
|
if (strcmp(stmt->label, estate->exitlabel) != 0)
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_EXIT;
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
|
2005-06-22 03:35:03 +02:00
|
|
|
case PLPGSQL_RC_CONTINUE:
|
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
/* anonymous continue, so re-run loop */
|
|
|
|
break;
|
|
|
|
else if (stmt->label != NULL &&
|
|
|
|
strcmp(stmt->label, estate->exitlabel) == 0)
|
|
|
|
/* label matches named continue, so re-run loop */
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
else
|
|
|
|
/* label doesn't match named continue, propagate upward */
|
|
|
|
return PLPGSQL_RC_CONTINUE;
|
|
|
|
break;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
case PLPGSQL_RC_RETURN:
|
2008-05-14 00:10:30 +02:00
|
|
|
return rc;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
|
|
|
default:
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized rc: %d", rc);
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_fori Iterate an integer variable
|
2006-06-12 18:45:30 +02:00
|
|
|
* from a lower to an upper value
|
2007-07-15 04:15:04 +02:00
|
|
|
* incrementing or decrementing by the BY value
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
PLpgSQL_var *var;
|
|
|
|
Datum value;
|
2005-06-22 03:35:03 +02:00
|
|
|
bool isnull;
|
2007-07-15 04:15:04 +02:00
|
|
|
Oid valtype;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 valtypmod;
|
2007-07-15 04:15:04 +02:00
|
|
|
int32 loop_value;
|
|
|
|
int32 end_value;
|
|
|
|
int32 step_value;
|
2002-08-20 07:28:24 +02:00
|
|
|
bool found = false;
|
|
|
|
int rc = PLPGSQL_RC_OK;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2008-11-05 01:07:54 +01:00
|
|
|
var = (PLpgSQL_var *) (estate->datums[stmt->var->dno]);
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2007-07-15 04:15:04 +02:00
|
|
|
* Get the value of the lower bound
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
value = exec_eval_expr(estate, stmt->lower,
|
|
|
|
&isnull, &valtype, &valtypmod);
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
value = exec_cast_value(estate, value, &isnull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
valtype, valtypmod,
|
|
|
|
var->datatype->typoid,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
var->datatype->atttypmod);
|
1998-09-01 06:40:42 +02:00
|
|
|
if (isnull)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("lower bound of FOR loop cannot be null")));
|
2007-07-15 04:15:04 +02:00
|
|
|
loop_value = DatumGetInt32(value);
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(estate);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Get the value of the upper bound
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
value = exec_eval_expr(estate, stmt->upper,
|
|
|
|
&isnull, &valtype, &valtypmod);
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
value = exec_cast_value(estate, value, &isnull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
valtype, valtypmod,
|
|
|
|
var->datatype->typoid,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
var->datatype->atttypmod);
|
1998-09-01 06:40:42 +02:00
|
|
|
if (isnull)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("upper bound of FOR loop cannot be null")));
|
2007-07-15 04:15:04 +02:00
|
|
|
end_value = DatumGetInt32(value);
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(estate);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2006-06-12 18:45:30 +02:00
|
|
|
/*
|
2007-07-15 04:15:04 +02:00
|
|
|
* Get the step value
|
2006-06-12 18:45:30 +02:00
|
|
|
*/
|
2007-07-15 04:15:04 +02:00
|
|
|
if (stmt->step)
|
|
|
|
{
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
value = exec_eval_expr(estate, stmt->step,
|
|
|
|
&isnull, &valtype, &valtypmod);
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
value = exec_cast_value(estate, value, &isnull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
valtype, valtypmod,
|
|
|
|
var->datatype->typoid,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
var->datatype->atttypmod);
|
2007-07-15 04:15:04 +02:00
|
|
|
if (isnull)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("BY value of FOR loop cannot be null")));
|
2007-07-15 04:15:04 +02:00
|
|
|
step_value = DatumGetInt32(value);
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
if (step_value <= 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("BY value of FOR loop must be greater than zero")));
|
2007-07-15 04:15:04 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
step_value = 1;
|
2006-06-12 18:45:30 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Now do the loop
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2007-07-15 04:15:04 +02:00
|
|
|
* Check against upper bound
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
if (stmt->reverse)
|
|
|
|
{
|
2007-07-15 04:15:04 +02:00
|
|
|
if (loop_value < end_value)
|
1998-09-01 06:40:42 +02:00
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
else
|
|
|
|
{
|
2007-07-15 04:15:04 +02:00
|
|
|
if (loop_value > end_value)
|
1998-09-01 06:40:42 +02:00
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
2002-08-20 07:28:24 +02:00
|
|
|
|
2002-09-04 22:31:48 +02:00
|
|
|
found = true; /* looped at least once */
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2007-07-15 04:15:04 +02:00
|
|
|
/*
|
|
|
|
* Assign current value to loop var
|
|
|
|
*/
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(estate, var, Int32GetDatum(loop_value), false, false);
|
2007-07-15 04:15:04 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Execute the statements
|
|
|
|
*/
|
|
|
|
rc = exec_stmts(estate, stmt->body);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2010-08-09 04:25:07 +02:00
|
|
|
if (rc == PLPGSQL_RC_RETURN)
|
2008-05-14 00:10:30 +02:00
|
|
|
break; /* break out of the loop */
|
2002-08-20 07:28:24 +02:00
|
|
|
else if (rc == PLPGSQL_RC_EXIT)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2002-08-20 07:28:24 +02:00
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
/* unlabelled exit, finish the current loop */
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
else if (stmt->label != NULL &&
|
|
|
|
strcmp(stmt->label, estate->exitlabel) == 0)
|
|
|
|
{
|
|
|
|
/* labelled exit, matches the current stmt's label */
|
1998-09-01 06:40:42 +02:00
|
|
|
estate->exitlabel = NULL;
|
2002-08-20 07:28:24 +02:00
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2002-08-20 07:28:24 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* otherwise, this is a labelled exit that does not match the
|
|
|
|
* current statement's label, if any: return RC_EXIT so that the
|
|
|
|
* EXIT continues to propagate up the stack.
|
2002-08-20 07:28:24 +02:00
|
|
|
*/
|
|
|
|
break;
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
2005-06-22 03:35:03 +02:00
|
|
|
else if (rc == PLPGSQL_RC_CONTINUE)
|
|
|
|
{
|
|
|
|
if (estate->exitlabel == NULL)
|
2007-07-15 04:15:04 +02:00
|
|
|
/* unlabelled continue, so re-run the current loop */
|
2005-06-22 09:28:47 +02:00
|
|
|
rc = PLPGSQL_RC_OK;
|
2005-06-22 03:35:03 +02:00
|
|
|
else if (stmt->label != NULL &&
|
|
|
|
strcmp(stmt->label, estate->exitlabel) == 0)
|
|
|
|
{
|
2005-06-22 09:28:47 +02:00
|
|
|
/* label matches named continue, so re-run loop */
|
2005-06-22 03:35:03 +02:00
|
|
|
estate->exitlabel = NULL;
|
2005-06-22 09:28:47 +02:00
|
|
|
rc = PLPGSQL_RC_OK;
|
2005-06-22 03:35:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2005-07-28 02:26:30 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* otherwise, this is a named continue that does not match the
|
|
|
|
* current statement's label, if any: return RC_CONTINUE so
|
|
|
|
* that the CONTINUE will propagate up the stack.
|
2005-06-22 03:35:03 +02:00
|
|
|
*/
|
2005-10-15 04:49:52 +02:00
|
|
|
break;
|
2005-06-22 03:35:03 +02:00
|
|
|
}
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2007-07-15 04:15:04 +02:00
|
|
|
* Increase/decrease loop value, unless it would overflow, in which
|
|
|
|
* case exit the loop.
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
if (stmt->reverse)
|
2007-07-15 04:15:04 +02:00
|
|
|
{
|
|
|
|
if ((int32) (loop_value - step_value) > loop_value)
|
|
|
|
break;
|
|
|
|
loop_value -= step_value;
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
else
|
2007-07-15 04:15:04 +02:00
|
|
|
{
|
|
|
|
if ((int32) (loop_value + step_value) < loop_value)
|
|
|
|
break;
|
|
|
|
loop_value += step_value;
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2002-08-20 07:28:24 +02:00
|
|
|
/*
|
2002-09-04 22:31:48 +02:00
|
|
|
* Set the FOUND variable to indicate the result of executing the loop
|
2005-10-15 04:49:52 +02:00
|
|
|
* (namely, whether we looped one or more times). This must be set here so
|
|
|
|
* that it does not interfere with the value of the FOUND variable inside
|
|
|
|
* the loop processing itself.
|
2002-08-20 07:28:24 +02:00
|
|
|
*/
|
|
|
|
exec_set_found(estate, found);
|
|
|
|
|
|
|
|
return rc;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_fors Execute a query, assign each
|
|
|
|
* tuple to a record or row and
|
|
|
|
* execute a group of statements
|
|
|
|
* for it.
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2001-05-21 16:22:19 +02:00
|
|
|
Portal portal;
|
2008-04-07 01:43:29 +02:00
|
|
|
int rc;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2008-04-07 01:43:29 +02:00
|
|
|
* Open the implicit cursor for the statement using exec_run_select
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
exec_run_select(estate, stmt->query, 0, &portal);
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2008-04-07 01:43:29 +02:00
|
|
|
* Execute the loop
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2008-04-07 01:43:29 +02:00
|
|
|
rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2008-04-07 01:43:29 +02:00
|
|
|
* Close the implicit cursor
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2008-04-07 01:43:29 +02:00
|
|
|
SPI_cursor_close(portal);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
return rc;
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2005-06-22 03:35:03 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/* ----------
|
|
|
|
* exec_stmt_forc Execute a loop for each row from a cursor.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
|
|
|
|
{
|
|
|
|
PLpgSQL_var *curvar;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext stmt_mcontext = NULL;
|
2008-04-07 01:43:29 +02:00
|
|
|
char *curname = NULL;
|
|
|
|
PLpgSQL_expr *query;
|
2009-11-04 23:26:08 +01:00
|
|
|
ParamListInfo paramLI;
|
2008-04-07 01:43:29 +02:00
|
|
|
Portal portal;
|
|
|
|
int rc;
|
2005-06-22 03:35:03 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/* ----------
|
|
|
|
* Get the cursor variable and if it has an assigned name, check
|
|
|
|
* that it's not in use currently.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
|
|
|
|
if (!curvar->isnull)
|
|
|
|
{
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
/* We only need stmt_mcontext to hold the cursor name string */
|
|
|
|
stmt_mcontext = get_stmt_mcontext(estate);
|
|
|
|
oldcontext = MemoryContextSwitchTo(stmt_mcontext);
|
2008-04-07 01:43:29 +02:00
|
|
|
curname = TextDatumGetCString(curvar->value);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
if (SPI_cursor_find(curname) != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_CURSOR),
|
|
|
|
errmsg("cursor \"%s\" already in use", curname)));
|
|
|
|
}
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/* ----------
|
|
|
|
* Open the cursor just like an OPEN command
|
|
|
|
*
|
|
|
|
* Note: parser should already have checked that statement supplies
|
|
|
|
* args iff cursor needs them, but we check again to be safe.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (stmt->argquery != NULL)
|
|
|
|
{
|
|
|
|
/* ----------
|
|
|
|
* OPEN CURSOR with args. We fake a SELECT ... INTO ...
|
|
|
|
* statement to evaluate the args and put 'em into the
|
|
|
|
* internal row.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
PLpgSQL_stmt_execsql set_args;
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
if (curvar->cursor_explicit_argrow < 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2009-06-11 16:49:15 +02:00
|
|
|
errmsg("arguments given for cursor without arguments")));
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
memset(&set_args, 0, sizeof(set_args));
|
|
|
|
set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
|
|
|
|
set_args.lineno = stmt->lineno;
|
|
|
|
set_args.sqlstmt = stmt->argquery;
|
|
|
|
set_args.into = true;
|
|
|
|
/* XXX historically this has not been STRICT */
|
|
|
|
set_args.row = (PLpgSQL_row *)
|
|
|
|
(estate->datums[curvar->cursor_explicit_argrow]);
|
|
|
|
|
|
|
|
if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
|
|
|
|
elog(ERROR, "open cursor failed during argument processing");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (curvar->cursor_explicit_argrow >= 0)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("arguments required for cursor")));
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
query = curvar->cursor_explicit_expr;
|
|
|
|
Assert(query);
|
|
|
|
|
|
|
|
if (query->plan == NULL)
|
|
|
|
exec_prepare_plan(estate, query, curvar->cursor_options);
|
|
|
|
|
2003-03-02 21:45:47 +01:00
|
|
|
/*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* Set up short-lived ParamListInfo
|
2003-03-02 21:45:47 +01:00
|
|
|
*/
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
paramLI = setup_unshared_param_list(estate, query);
|
2003-03-02 21:45:47 +01:00
|
|
|
|
2001-05-21 16:22:19 +02:00
|
|
|
/*
|
2009-11-04 23:26:08 +01:00
|
|
|
* Open the cursor (the paramlist will get copied into the portal)
|
2001-05-21 16:22:19 +02:00
|
|
|
*/
|
2009-11-04 23:26:08 +01:00
|
|
|
portal = SPI_cursor_open_with_paramlist(curname, query->plan,
|
|
|
|
paramLI,
|
|
|
|
estate->readonly_func);
|
2008-04-07 01:43:29 +02:00
|
|
|
if (portal == NULL)
|
|
|
|
elog(ERROR, "could not open cursor: %s",
|
|
|
|
SPI_result_code_string(SPI_result));
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2002-08-20 07:28:24 +02:00
|
|
|
/*
|
2008-04-07 01:43:29 +02:00
|
|
|
* If cursor variable was NULL, store the generated portal name in it
|
2002-08-20 07:28:24 +02:00
|
|
|
*/
|
2008-04-07 01:43:29 +02:00
|
|
|
if (curname == NULL)
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(estate, curvar, portal->name);
|
2008-04-07 01:43:29 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* Clean up before entering exec_for_query
|
|
|
|
*/
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
if (stmt_mcontext)
|
|
|
|
MemoryContextReset(stmt_mcontext);
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
|
|
|
* Execute the loop. We can't prefetch because the cursor is accessible
|
|
|
|
* to the user, for instance via UPDATE WHERE CURRENT OF within the loop.
|
|
|
|
*/
|
|
|
|
rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, false);
|
|
|
|
|
|
|
|
/* ----------
|
2010-07-05 11:27:18 +02:00
|
|
|
* Close portal, and restore cursor variable if it was initially NULL.
|
2008-04-07 01:43:29 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
SPI_cursor_close(portal);
|
|
|
|
|
|
|
|
if (curname == NULL)
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(estate, curvar, (Datum) 0, true, false);
|
2008-04-07 01:43:29 +02:00
|
|
|
|
2002-08-20 07:28:24 +02:00
|
|
|
return rc;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-02-16 07:52:04 +01:00
|
|
|
/* ----------
|
|
|
|
* exec_stmt_foreach_a Loop over elements or slices of an array
|
|
|
|
*
|
|
|
|
* When looping over elements, the loop variable is the same type that the
|
|
|
|
* array stores (eg: integer), when looping through slices, the loop variable
|
|
|
|
* is an array of size and dimensions to match the size of the slice.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
|
|
|
|
{
|
2011-04-10 17:42:00 +02:00
|
|
|
ArrayType *arr;
|
|
|
|
Oid arrtype;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 arrtypmod;
|
2011-04-10 17:42:00 +02:00
|
|
|
PLpgSQL_datum *loop_var;
|
|
|
|
Oid loop_var_elem_type;
|
|
|
|
bool found = false;
|
|
|
|
int rc = PLPGSQL_RC_OK;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext stmt_mcontext;
|
|
|
|
MemoryContext oldcontext;
|
2011-04-10 17:42:00 +02:00
|
|
|
ArrayIterator array_iterator;
|
|
|
|
Oid iterator_result_type;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 iterator_result_typmod;
|
2011-04-10 17:42:00 +02:00
|
|
|
Datum value;
|
|
|
|
bool isnull;
|
2011-02-16 07:52:04 +01:00
|
|
|
|
|
|
|
/* get the value of the array expression */
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
value = exec_eval_expr(estate, stmt->expr, &isnull, &arrtype, &arrtypmod);
|
2011-02-16 07:52:04 +01:00
|
|
|
if (isnull)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2011-05-20 23:50:35 +02:00
|
|
|
errmsg("FOREACH expression must not be null")));
|
2011-02-16 07:52:04 +01:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* Do as much as possible of the code below in stmt_mcontext, to avoid any
|
|
|
|
* leaks from called subroutines. We need a private stmt_mcontext since
|
|
|
|
* we'll be calling arbitrary statement code.
|
|
|
|
*/
|
|
|
|
stmt_mcontext = get_stmt_mcontext(estate);
|
|
|
|
push_stmt_mcontext(estate);
|
|
|
|
oldcontext = MemoryContextSwitchTo(stmt_mcontext);
|
|
|
|
|
2011-02-16 07:52:04 +01:00
|
|
|
/* check the type of the expression - must be an array */
|
|
|
|
if (!OidIsValid(get_element_type(arrtype)))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("FOREACH expression must yield an array, not type %s",
|
|
|
|
format_type_be(arrtype))));
|
|
|
|
|
|
|
|
/*
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* We must copy the array into stmt_mcontext, else it will disappear in
|
|
|
|
* exec_eval_cleanup. This is annoying, but cleanup will certainly happen
|
|
|
|
* while running the loop body, so we have little choice.
|
2011-02-16 07:52:04 +01:00
|
|
|
*/
|
|
|
|
arr = DatumGetArrayTypePCopy(value);
|
|
|
|
|
|
|
|
/* Clean up any leftover temporary memory */
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
|
|
|
|
/* Slice dimension must be less than or equal to array dimension */
|
|
|
|
if (stmt->slice < 0 || stmt->slice > ARR_NDIM(arr))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ARRAY_SUBSCRIPT_ERROR),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("slice dimension (%d) is out of the valid range 0..%d",
|
|
|
|
stmt->slice, ARR_NDIM(arr))));
|
2011-02-16 07:52:04 +01:00
|
|
|
|
|
|
|
/* Set up the loop variable and see if it is of an array type */
|
|
|
|
loop_var = estate->datums[stmt->varno];
|
|
|
|
if (loop_var->dtype == PLPGSQL_DTYPE_REC ||
|
|
|
|
loop_var->dtype == PLPGSQL_DTYPE_ROW)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Record/row variable is certainly not of array type, and might not
|
|
|
|
* be initialized at all yet, so don't try to get its type
|
|
|
|
*/
|
|
|
|
loop_var_elem_type = InvalidOid;
|
|
|
|
}
|
|
|
|
else
|
2016-03-03 10:45:59 +01:00
|
|
|
loop_var_elem_type = get_element_type(plpgsql_exec_get_datum_type(estate,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
loop_var));
|
2011-02-16 07:52:04 +01:00
|
|
|
|
|
|
|
/*
|
2011-04-10 17:42:00 +02:00
|
|
|
* Sanity-check the loop variable type. We don't try very hard here, and
|
|
|
|
* should not be too picky since it's possible that exec_assign_value can
|
|
|
|
* coerce values of different types. But it seems worthwhile to complain
|
|
|
|
* if the array-ness of the loop variable is not right.
|
2011-02-16 07:52:04 +01:00
|
|
|
*/
|
|
|
|
if (stmt->slice > 0 && loop_var_elem_type == InvalidOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("FOREACH ... SLICE loop variable must be of an array type")));
|
2011-02-16 07:52:04 +01:00
|
|
|
if (stmt->slice == 0 && loop_var_elem_type != InvalidOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("FOREACH loop variable must not be of an array type")));
|
2011-02-16 07:52:04 +01:00
|
|
|
|
|
|
|
/* Create an iterator to step through the array */
|
2015-03-18 20:01:34 +01:00
|
|
|
array_iterator = array_create_iterator(arr, stmt->slice, NULL);
|
2011-02-16 07:52:04 +01:00
|
|
|
|
|
|
|
/* Identify iterator result type */
|
|
|
|
if (stmt->slice > 0)
|
|
|
|
{
|
|
|
|
/* When slicing, nominal type of result is same as array type */
|
|
|
|
iterator_result_type = arrtype;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
iterator_result_typmod = arrtypmod;
|
2011-02-16 07:52:04 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Without slicing, results are individual array elements */
|
|
|
|
iterator_result_type = ARR_ELEMTYPE(arr);
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
iterator_result_typmod = arrtypmod;
|
2011-02-16 07:52:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Iterate over the array elements or slices */
|
|
|
|
while (array_iterate(array_iterator, &value, &isnull))
|
|
|
|
{
|
|
|
|
found = true; /* looped at least once */
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* exec_assign_value and exec_stmts must run in the main context */
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2011-02-16 07:52:04 +01:00
|
|
|
/* Assign current element/slice to the loop variable */
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
exec_assign_value(estate, loop_var, value, isnull,
|
|
|
|
iterator_result_type, iterator_result_typmod);
|
2011-02-16 07:52:04 +01:00
|
|
|
|
|
|
|
/* In slice case, value is temporary; must free it to avoid leakage */
|
|
|
|
if (stmt->slice > 0)
|
|
|
|
pfree(DatumGetPointer(value));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Execute the statements
|
|
|
|
*/
|
|
|
|
rc = exec_stmts(estate, stmt->body);
|
|
|
|
|
|
|
|
/* Handle the return code */
|
|
|
|
if (rc == PLPGSQL_RC_RETURN)
|
|
|
|
break; /* break out of the loop */
|
|
|
|
else if (rc == PLPGSQL_RC_EXIT)
|
|
|
|
{
|
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
/* unlabelled exit, finish the current loop */
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
else if (stmt->label != NULL &&
|
|
|
|
strcmp(stmt->label, estate->exitlabel) == 0)
|
|
|
|
{
|
|
|
|
/* labelled exit, matches the current stmt's label */
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* otherwise, this is a labelled exit that does not match the
|
|
|
|
* current statement's label, if any: return RC_EXIT so that the
|
|
|
|
* EXIT continues to propagate up the stack.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (rc == PLPGSQL_RC_CONTINUE)
|
|
|
|
{
|
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
/* unlabelled continue, so re-run the current loop */
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
else if (stmt->label != NULL &&
|
|
|
|
strcmp(stmt->label, estate->exitlabel) == 0)
|
|
|
|
{
|
|
|
|
/* label matches named continue, so re-run loop */
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* otherwise, this is a named continue that does not match the
|
|
|
|
* current statement's label, if any: return RC_CONTINUE so
|
|
|
|
* that the CONTINUE will propagate up the stack.
|
|
|
|
*/
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
|
|
|
|
MemoryContextSwitchTo(stmt_mcontext);
|
2011-02-16 07:52:04 +01:00
|
|
|
}
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Restore memory context state */
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
pop_stmt_mcontext(estate);
|
|
|
|
|
2011-02-16 07:52:04 +01:00
|
|
|
/* Release temporary memory, including the array value */
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextReset(stmt_mcontext);
|
2011-02-16 07:52:04 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Set the FOUND variable to indicate the result of executing the loop
|
|
|
|
* (namely, whether we looped one or more times). This must be set here so
|
|
|
|
* that it does not interfere with the value of the FOUND variable inside
|
|
|
|
* the loop processing itself.
|
|
|
|
*/
|
|
|
|
exec_set_found(estate, found);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
2005-06-22 03:35:03 +02:00
|
|
|
* exec_stmt_exit Implements EXIT and CONTINUE
|
|
|
|
*
|
|
|
|
* This begins the process of exiting / restarting a loop.
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_exit(PLpgSQL_execstate *estate, PLpgSQL_stmt_exit *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-06-22 03:35:03 +02:00
|
|
|
* If the exit / continue has a condition, evaluate it
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
if (stmt->cond != NULL)
|
|
|
|
{
|
2003-10-01 23:47:42 +02:00
|
|
|
bool value;
|
2005-06-22 03:35:03 +02:00
|
|
|
bool isnull;
|
2003-10-01 23:47:42 +02:00
|
|
|
|
|
|
|
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(estate);
|
2005-06-22 03:35:03 +02:00
|
|
|
if (isnull || value == false)
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
estate->exitlabel = stmt->label;
|
2005-06-22 03:35:03 +02:00
|
|
|
if (stmt->is_exit)
|
|
|
|
return PLPGSQL_RC_EXIT;
|
|
|
|
else
|
|
|
|
return PLPGSQL_RC_CONTINUE;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_return Evaluate an expression and start
|
|
|
|
* returning from the function.
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
*
|
|
|
|
* Note: in the retistuple code paths, the returned tuple is always in the
|
|
|
|
* function's main context, whereas for non-tuple data types the result may
|
|
|
|
* be in the eval_mcontext. The former case is not a memory leak since we're
|
|
|
|
* about to exit the function anyway. (If you want to change it, note that
|
|
|
|
* exec_stmt_block() knows about this behavior.) The latter case means that
|
|
|
|
* we must not do exec_eval_cleanup while unwinding the control stack.
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2002-08-30 02:28:41 +02:00
|
|
|
/*
|
2010-09-23 03:57:37 +02:00
|
|
|
* If processing a set-returning PL/pgSQL function, the final RETURN
|
2005-10-15 04:49:52 +02:00
|
|
|
* indicates that the function is finished producing tuples. The rest of
|
|
|
|
* the work will be done at the top level.
|
2002-08-30 02:28:41 +02:00
|
|
|
*/
|
|
|
|
if (estate->retisset)
|
|
|
|
return PLPGSQL_RC_RETURN;
|
|
|
|
|
2005-04-05 08:22:17 +02:00
|
|
|
/* initialize for null result (possibly a tuple) */
|
|
|
|
estate->retval = (Datum) 0;
|
|
|
|
estate->rettupdesc = NULL;
|
|
|
|
estate->retisnull = true;
|
Fix failure to cover scalar-vs-rowtype cases in exec_stmt_return().
In commit 9e3ad1aac52454569393a947c06be0d301749362 I modified plpgsql
to use exec_stmt_return's simple-variables fast path in more cases.
However, I overlooked that there are really two different return
conventions in use here, depending on whether estate->retistuple is true,
and the existing fast-path code had only bothered to handle one of them.
So trying to return a scalar in a function returning composite, or vice
versa, could lead to unexpected error messages (typically "cache lookup
failed for type 0") or to a null-pointer-dereference crash.
In the DTYPE_VAR case, we can just throw error if retistuple is true,
corresponding to what happens in the general-expression code path that was
being used previously. (Perhaps someday both of these code paths should
attempt a coercion, but today is not that day.)
In the REC and ROW cases, just hand the problem to exec_eval_datum()
when not retistuple. Also clean up the ROW coding slightly so it looks
more like exec_eval_datum().
The previous commit also caused exec_stmt_return_next() to be used in
more cases, but that code seems to be OK as-is.
Per off-list report from Serge Rielau. This bug is new in 9.5 so no need
to back-patch.
2015-06-12 19:44:06 +02:00
|
|
|
estate->rettype = InvalidOid;
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2012-12-07 05:09:52 +01:00
|
|
|
/*
|
2015-02-16 21:28:40 +01:00
|
|
|
* Special case path when the RETURN expression is a simple variable
|
|
|
|
* reference; in particular, this path is always taken in functions with
|
|
|
|
* one or more OUT parameters.
|
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
|
|
|
*
|
|
|
|
* This special case is especially efficient for returning variables that
|
|
|
|
* have R/W expanded values: we can put the R/W pointer directly into
|
|
|
|
* estate->retval, leading to transferring the value to the caller's
|
|
|
|
* context cheaply. If we went through exec_eval_expr we'd end up with a
|
|
|
|
* R/O pointer. It's okay to skip MakeExpandedObjectReadOnly here since
|
|
|
|
* we know we won't need the variable's value within the function anymore.
|
2012-12-07 05:09:52 +01:00
|
|
|
*/
|
2005-04-05 08:22:17 +02:00
|
|
|
if (stmt->retvarno >= 0)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2005-04-05 08:22:17 +02:00
|
|
|
PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2005-04-05 08:22:17 +02:00
|
|
|
switch (retvar->dtype)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2005-04-05 08:22:17 +02:00
|
|
|
case PLPGSQL_DTYPE_VAR:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) retvar;
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
estate->retval = var->value;
|
|
|
|
estate->retisnull = var->isnull;
|
|
|
|
estate->rettype = var->datatype->typoid;
|
Fix failure to cover scalar-vs-rowtype cases in exec_stmt_return().
In commit 9e3ad1aac52454569393a947c06be0d301749362 I modified plpgsql
to use exec_stmt_return's simple-variables fast path in more cases.
However, I overlooked that there are really two different return
conventions in use here, depending on whether estate->retistuple is true,
and the existing fast-path code had only bothered to handle one of them.
So trying to return a scalar in a function returning composite, or vice
versa, could lead to unexpected error messages (typically "cache lookup
failed for type 0") or to a null-pointer-dereference crash.
In the DTYPE_VAR case, we can just throw error if retistuple is true,
corresponding to what happens in the general-expression code path that was
being used previously. (Perhaps someday both of these code paths should
attempt a coercion, but today is not that day.)
In the REC and ROW cases, just hand the problem to exec_eval_datum()
when not retistuple. Also clean up the ROW coding slightly so it looks
more like exec_eval_datum().
The previous commit also caused exec_stmt_return_next() to be used in
more cases, but that code seems to be OK as-is.
Per off-list report from Serge Rielau. This bug is new in 9.5 so no need
to back-patch.
2015-06-12 19:44:06 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Cope with retistuple case. A PLpgSQL_var could not be
|
|
|
|
* of composite type, so we needn't make any effort to
|
|
|
|
* convert. However, for consistency with the expression
|
|
|
|
* code path, don't throw error if the result is NULL.
|
|
|
|
*/
|
|
|
|
if (estate->retistuple && !estate->retisnull)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("cannot return non-composite value from function returning composite type")));
|
2005-10-15 04:49:52 +02:00
|
|
|
}
|
|
|
|
break;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2005-04-05 08:22:17 +02:00
|
|
|
case PLPGSQL_DTYPE_REC:
|
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
|
Fix failure to cover scalar-vs-rowtype cases in exec_stmt_return().
In commit 9e3ad1aac52454569393a947c06be0d301749362 I modified plpgsql
to use exec_stmt_return's simple-variables fast path in more cases.
However, I overlooked that there are really two different return
conventions in use here, depending on whether estate->retistuple is true,
and the existing fast-path code had only bothered to handle one of them.
So trying to return a scalar in a function returning composite, or vice
versa, could lead to unexpected error messages (typically "cache lookup
failed for type 0") or to a null-pointer-dereference crash.
In the DTYPE_VAR case, we can just throw error if retistuple is true,
corresponding to what happens in the general-expression code path that was
being used previously. (Perhaps someday both of these code paths should
attempt a coercion, but today is not that day.)
In the REC and ROW cases, just hand the problem to exec_eval_datum()
when not retistuple. Also clean up the ROW coding slightly so it looks
more like exec_eval_datum().
The previous commit also caused exec_stmt_return_next() to be used in
more cases, but that code seems to be OK as-is.
Per off-list report from Serge Rielau. This bug is new in 9.5 so no need
to back-patch.
2015-06-12 19:44:06 +02:00
|
|
|
int32 rettypmod;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
|
|
|
if (HeapTupleIsValid(rec->tup))
|
|
|
|
{
|
Fix failure to cover scalar-vs-rowtype cases in exec_stmt_return().
In commit 9e3ad1aac52454569393a947c06be0d301749362 I modified plpgsql
to use exec_stmt_return's simple-variables fast path in more cases.
However, I overlooked that there are really two different return
conventions in use here, depending on whether estate->retistuple is true,
and the existing fast-path code had only bothered to handle one of them.
So trying to return a scalar in a function returning composite, or vice
versa, could lead to unexpected error messages (typically "cache lookup
failed for type 0") or to a null-pointer-dereference crash.
In the DTYPE_VAR case, we can just throw error if retistuple is true,
corresponding to what happens in the general-expression code path that was
being used previously. (Perhaps someday both of these code paths should
attempt a coercion, but today is not that day.)
In the REC and ROW cases, just hand the problem to exec_eval_datum()
when not retistuple. Also clean up the ROW coding slightly so it looks
more like exec_eval_datum().
The previous commit also caused exec_stmt_return_next() to be used in
more cases, but that code seems to be OK as-is.
Per off-list report from Serge Rielau. This bug is new in 9.5 so no need
to back-patch.
2015-06-12 19:44:06 +02:00
|
|
|
if (estate->retistuple)
|
|
|
|
{
|
|
|
|
estate->retval = PointerGetDatum(rec->tup);
|
|
|
|
estate->rettupdesc = rec->tupdesc;
|
|
|
|
estate->retisnull = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
exec_eval_datum(estate,
|
|
|
|
retvar,
|
|
|
|
&estate->rettype,
|
|
|
|
&rettypmod,
|
|
|
|
&estate->retval,
|
|
|
|
&estate->retisnull);
|
2005-10-15 04:49:52 +02:00
|
|
|
}
|
2005-04-05 08:22:17 +02:00
|
|
|
}
|
2005-10-15 04:49:52 +02:00
|
|
|
break;
|
2003-09-26 01:02:12 +02:00
|
|
|
|
2005-04-05 08:22:17 +02:00
|
|
|
case PLPGSQL_DTYPE_ROW:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_row *row = (PLpgSQL_row *) retvar;
|
Fix failure to cover scalar-vs-rowtype cases in exec_stmt_return().
In commit 9e3ad1aac52454569393a947c06be0d301749362 I modified plpgsql
to use exec_stmt_return's simple-variables fast path in more cases.
However, I overlooked that there are really two different return
conventions in use here, depending on whether estate->retistuple is true,
and the existing fast-path code had only bothered to handle one of them.
So trying to return a scalar in a function returning composite, or vice
versa, could lead to unexpected error messages (typically "cache lookup
failed for type 0") or to a null-pointer-dereference crash.
In the DTYPE_VAR case, we can just throw error if retistuple is true,
corresponding to what happens in the general-expression code path that was
being used previously. (Perhaps someday both of these code paths should
attempt a coercion, but today is not that day.)
In the REC and ROW cases, just hand the problem to exec_eval_datum()
when not retistuple. Also clean up the ROW coding slightly so it looks
more like exec_eval_datum().
The previous commit also caused exec_stmt_return_next() to be used in
more cases, but that code seems to be OK as-is.
Per off-list report from Serge Rielau. This bug is new in 9.5 so no need
to back-patch.
2015-06-12 19:44:06 +02:00
|
|
|
int32 rettypmod;
|
2005-10-15 04:49:52 +02:00
|
|
|
|
Fix failure to cover scalar-vs-rowtype cases in exec_stmt_return().
In commit 9e3ad1aac52454569393a947c06be0d301749362 I modified plpgsql
to use exec_stmt_return's simple-variables fast path in more cases.
However, I overlooked that there are really two different return
conventions in use here, depending on whether estate->retistuple is true,
and the existing fast-path code had only bothered to handle one of them.
So trying to return a scalar in a function returning composite, or vice
versa, could lead to unexpected error messages (typically "cache lookup
failed for type 0") or to a null-pointer-dereference crash.
In the DTYPE_VAR case, we can just throw error if retistuple is true,
corresponding to what happens in the general-expression code path that was
being used previously. (Perhaps someday both of these code paths should
attempt a coercion, but today is not that day.)
In the REC and ROW cases, just hand the problem to exec_eval_datum()
when not retistuple. Also clean up the ROW coding slightly so it looks
more like exec_eval_datum().
The previous commit also caused exec_stmt_return_next() to be used in
more cases, but that code seems to be OK as-is.
Per off-list report from Serge Rielau. This bug is new in 9.5 so no need
to back-patch.
2015-06-12 19:44:06 +02:00
|
|
|
if (estate->retistuple)
|
|
|
|
{
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
if (!row->rowtupdesc) /* should not happen */
|
|
|
|
elog(ERROR, "row variable has no tupdesc");
|
|
|
|
tup = make_tuple_from_row(estate, row, row->rowtupdesc);
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
if (tup == NULL) /* should not happen */
|
Fix failure to cover scalar-vs-rowtype cases in exec_stmt_return().
In commit 9e3ad1aac52454569393a947c06be0d301749362 I modified plpgsql
to use exec_stmt_return's simple-variables fast path in more cases.
However, I overlooked that there are really two different return
conventions in use here, depending on whether estate->retistuple is true,
and the existing fast-path code had only bothered to handle one of them.
So trying to return a scalar in a function returning composite, or vice
versa, could lead to unexpected error messages (typically "cache lookup
failed for type 0") or to a null-pointer-dereference crash.
In the DTYPE_VAR case, we can just throw error if retistuple is true,
corresponding to what happens in the general-expression code path that was
being used previously. (Perhaps someday both of these code paths should
attempt a coercion, but today is not that day.)
In the REC and ROW cases, just hand the problem to exec_eval_datum()
when not retistuple. Also clean up the ROW coding slightly so it looks
more like exec_eval_datum().
The previous commit also caused exec_stmt_return_next() to be used in
more cases, but that code seems to be OK as-is.
Per off-list report from Serge Rielau. This bug is new in 9.5 so no need
to back-patch.
2015-06-12 19:44:06 +02:00
|
|
|
elog(ERROR, "row not compatible with its own tupdesc");
|
|
|
|
estate->retval = PointerGetDatum(tup);
|
|
|
|
estate->rettupdesc = row->rowtupdesc;
|
|
|
|
estate->retisnull = false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
exec_eval_datum(estate,
|
|
|
|
retvar,
|
|
|
|
&estate->rettype,
|
|
|
|
&rettypmod,
|
|
|
|
&estate->retval,
|
|
|
|
&estate->retisnull);
|
2005-10-15 04:49:52 +02:00
|
|
|
}
|
|
|
|
break;
|
2005-04-05 08:22:17 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
|
2003-09-26 01:02:12 +02:00
|
|
|
}
|
|
|
|
|
2005-04-05 08:22:17 +02:00
|
|
|
return PLPGSQL_RC_RETURN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stmt->expr != NULL)
|
|
|
|
{
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 rettypmod;
|
|
|
|
|
2012-12-07 05:09:52 +01:00
|
|
|
estate->retval = exec_eval_expr(estate, stmt->expr,
|
|
|
|
&(estate->retisnull),
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
&(estate->rettype),
|
|
|
|
&rettypmod);
|
2012-12-07 05:09:52 +01:00
|
|
|
|
|
|
|
if (estate->retistuple && !estate->retisnull)
|
2005-04-05 08:22:17 +02:00
|
|
|
{
|
2012-12-07 05:09:52 +01:00
|
|
|
/* Convert composite datum to a HeapTuple and TupleDesc */
|
|
|
|
HeapTuple tuple;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
|
|
|
|
/* Source must be of RECORD or composite type */
|
|
|
|
if (!type_is_rowtype(estate->rettype))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("cannot return non-composite value from function returning composite type")));
|
|
|
|
tuple = get_tuple_from_datum(estate->retval);
|
|
|
|
tupdesc = get_tupdesc_from_datum(estate->retval);
|
|
|
|
estate->retval = PointerGetDatum(tuple);
|
|
|
|
estate->rettupdesc = CreateTupleDescCopy(tupdesc);
|
|
|
|
ReleaseTupleDesc(tupdesc);
|
2005-04-05 08:22:17 +02:00
|
|
|
}
|
2005-04-07 16:53:04 +02:00
|
|
|
|
|
|
|
return PLPGSQL_RC_RETURN;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2005-04-07 16:53:04 +02:00
|
|
|
/*
|
|
|
|
* Special hack for function returning VOID: instead of NULL, return a
|
|
|
|
* non-null VOID value. This is of dubious importance but is kept for
|
2012-12-07 05:09:52 +01:00
|
|
|
* backwards compatibility.
|
2005-04-07 16:53:04 +02:00
|
|
|
*/
|
2002-08-30 02:28:41 +02:00
|
|
|
if (estate->fn_rettype == VOIDOID)
|
|
|
|
{
|
|
|
|
estate->retval = (Datum) 0;
|
|
|
|
estate->retisnull = false;
|
|
|
|
estate->rettype = VOIDOID;
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_RETURN;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2002-11-10 01:35:58 +01:00
|
|
|
/* ----------
|
|
|
|
* exec_stmt_return_next Evaluate an expression and add it to the
|
|
|
|
* list of tuples returned by the current
|
|
|
|
* SRF.
|
|
|
|
* ----------
|
2002-08-30 02:28:41 +02:00
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_return_next(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_return_next *stmt)
|
2002-08-30 02:28:41 +02:00
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
TupleDesc tupdesc;
|
|
|
|
int natts;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
HeapTuple tuple;
|
|
|
|
MemoryContext oldcontext;
|
2002-08-30 02:28:41 +02:00
|
|
|
|
|
|
|
if (!estate->retisset)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("cannot use RETURN NEXT in a non-SETOF function")));
|
2002-08-30 02:28:41 +02:00
|
|
|
|
|
|
|
if (estate->tuple_store == NULL)
|
|
|
|
exec_init_tuple_store(estate);
|
|
|
|
|
2002-08-31 01:59:46 +02:00
|
|
|
/* rettupdesc will be filled by exec_init_tuple_store */
|
|
|
|
tupdesc = estate->rettupdesc;
|
2002-09-04 22:31:48 +02:00
|
|
|
natts = tupdesc->natts;
|
2002-08-31 01:59:46 +02:00
|
|
|
|
2012-12-07 05:09:52 +01:00
|
|
|
/*
|
2015-02-16 21:28:40 +01:00
|
|
|
* Special case path when the RETURN NEXT expression is a simple variable
|
|
|
|
* reference; in particular, this path is always taken in functions with
|
|
|
|
* one or more OUT parameters.
|
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
|
|
|
*
|
|
|
|
* Unlike exec_statement_return, there's no special win here for R/W
|
|
|
|
* expanded values, since they'll have to get flattened to go into the
|
|
|
|
* tuplestore. Indeed, we'd better make them R/O to avoid any risk of the
|
|
|
|
* casting step changing them in-place.
|
2012-12-07 05:09:52 +01:00
|
|
|
*/
|
2005-04-05 08:22:17 +02:00
|
|
|
if (stmt->retvarno >= 0)
|
2002-08-30 02:28:41 +02:00
|
|
|
{
|
2005-04-05 08:22:17 +02:00
|
|
|
PLpgSQL_datum *retvar = estate->datums[stmt->retvarno];
|
2002-08-31 01:59:46 +02:00
|
|
|
|
2005-04-05 08:22:17 +02:00
|
|
|
switch (retvar->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_VAR:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) retvar;
|
|
|
|
Datum retval = var->value;
|
|
|
|
bool isNull = var->isnull;
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
if (natts != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("wrong result type supplied in RETURN NEXT")));
|
2005-04-05 08:22:17 +02:00
|
|
|
|
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
|
|
|
/* let's be very paranoid about the cast step */
|
|
|
|
retval = MakeExpandedObjectReadOnly(retval,
|
|
|
|
isNull,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
var->datatype->typlen);
|
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
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
/* coerce type if needed */
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
retval = exec_cast_value(estate,
|
|
|
|
retval,
|
|
|
|
&isNull,
|
|
|
|
var->datatype->typoid,
|
|
|
|
var->datatype->atttypmod,
|
2017-08-20 20:19:07 +02:00
|
|
|
attr->atttypid,
|
|
|
|
attr->atttypmod);
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2008-03-25 20:26:54 +01:00
|
|
|
tuplestore_putvalues(estate->tuple_store, tupdesc,
|
|
|
|
&retval, &isNull);
|
2005-10-15 04:49:52 +02:00
|
|
|
}
|
|
|
|
break;
|
2005-04-05 08:22:17 +02:00
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_REC:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) retvar;
|
2009-08-06 22:44:32 +02:00
|
|
|
TupleConversionMap *tupmap;
|
2005-04-05 08:22:17 +02:00
|
|
|
|
2005-10-15 04:49:52 +02:00
|
|
|
if (!HeapTupleIsValid(rec->tup))
|
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("record \"%s\" is not assigned yet",
|
|
|
|
rec->refname),
|
|
|
|
errdetail("The tuple structure of a not-yet-assigned"
|
|
|
|
" record is indeterminate.")));
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
|
|
|
|
/* Use eval_mcontext for tuple conversion work */
|
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2009-08-06 22:44:32 +02:00
|
|
|
tupmap = convert_tuples_by_position(rec->tupdesc,
|
|
|
|
tupdesc,
|
|
|
|
gettext_noop("wrong record type supplied in RETURN NEXT"));
|
2005-10-15 04:49:52 +02:00
|
|
|
tuple = rec->tup;
|
2009-08-06 22:44:32 +02:00
|
|
|
if (tupmap)
|
|
|
|
tuple = do_convert_tuple(tuple, tupmap);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
tuplestore_puttuple(estate->tuple_store, tuple);
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2005-10-15 04:49:52 +02:00
|
|
|
}
|
|
|
|
break;
|
2005-04-05 08:22:17 +02:00
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_ROW:
|
2005-10-15 04:49:52 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_row *row = (PLpgSQL_row *) retvar;
|
2005-04-05 08:22:17 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Use eval_mcontext for tuple conversion work */
|
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2005-10-15 04:49:52 +02:00
|
|
|
tuple = make_tuple_from_row(estate, row, tupdesc);
|
|
|
|
if (tuple == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("wrong record type supplied in RETURN NEXT")));
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
tuplestore_puttuple(estate->tuple_store, tuple);
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2005-10-15 04:49:52 +02:00
|
|
|
}
|
|
|
|
break;
|
2005-04-05 08:22:17 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized dtype: %d", retvar->dtype);
|
|
|
|
break;
|
|
|
|
}
|
2002-08-30 02:28:41 +02:00
|
|
|
}
|
|
|
|
else if (stmt->expr)
|
|
|
|
{
|
2002-09-04 22:31:48 +02:00
|
|
|
Datum retval;
|
|
|
|
bool isNull;
|
|
|
|
Oid rettype;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 rettypmod;
|
2002-08-30 02:28:41 +02:00
|
|
|
|
|
|
|
retval = exec_eval_expr(estate,
|
|
|
|
stmt->expr,
|
|
|
|
&isNull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
&rettype,
|
|
|
|
&rettypmod);
|
2002-08-31 01:59:46 +02:00
|
|
|
|
2012-12-07 05:09:52 +01:00
|
|
|
if (estate->retistuple)
|
|
|
|
{
|
|
|
|
/* Expression should be of RECORD or composite type */
|
|
|
|
if (!isNull)
|
|
|
|
{
|
|
|
|
TupleDesc retvaldesc;
|
|
|
|
TupleConversionMap *tupmap;
|
|
|
|
|
|
|
|
if (!type_is_rowtype(rettype))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("cannot return non-composite value from function returning composite type")));
|
2002-08-30 02:28:41 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Use eval_mcontext for tuple conversion work */
|
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2012-12-07 05:09:52 +01:00
|
|
|
tuple = get_tuple_from_datum(retval);
|
|
|
|
retvaldesc = get_tupdesc_from_datum(retval);
|
|
|
|
tupmap = convert_tuples_by_position(retvaldesc, tupdesc,
|
|
|
|
gettext_noop("returned record type does not match expected record type"));
|
|
|
|
if (tupmap)
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
tuple = do_convert_tuple(tuple, tupmap);
|
|
|
|
tuplestore_puttuple(estate->tuple_store, tuple);
|
2012-12-07 05:09:52 +01:00
|
|
|
ReleaseTupleDesc(retvaldesc);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2012-12-07 05:09:52 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Composite NULL --- store a row of nulls */
|
|
|
|
Datum *nulldatums;
|
|
|
|
bool *nullflags;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
nulldatums = (Datum *)
|
|
|
|
eval_mcontext_alloc0(estate, natts * sizeof(Datum));
|
|
|
|
nullflags = (bool *)
|
|
|
|
eval_mcontext_alloc(estate, natts * sizeof(bool));
|
2012-12-07 05:09:52 +01:00
|
|
|
memset(nullflags, true, natts * sizeof(bool));
|
|
|
|
tuplestore_putvalues(estate->tuple_store, tupdesc,
|
|
|
|
nulldatums, nullflags);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attr = TupleDescAttr(tupdesc, 0);
|
|
|
|
|
2012-12-07 05:09:52 +01:00
|
|
|
/* Simple scalar result */
|
|
|
|
if (natts != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("wrong result type supplied in RETURN NEXT")));
|
2012-12-07 05:09:52 +01:00
|
|
|
|
|
|
|
/* coerce type if needed */
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
retval = exec_cast_value(estate,
|
|
|
|
retval,
|
|
|
|
&isNull,
|
|
|
|
rettype,
|
|
|
|
rettypmod,
|
2017-08-20 20:19:07 +02:00
|
|
|
attr->atttypid,
|
|
|
|
attr->atttypmod);
|
2012-12-07 05:09:52 +01:00
|
|
|
|
|
|
|
tuplestore_putvalues(estate->tuple_store, tupdesc,
|
|
|
|
&retval, &isNull);
|
|
|
|
}
|
2002-08-30 02:28:41 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("RETURN NEXT must have a parameter")));
|
2002-08-30 02:28:41 +02:00
|
|
|
}
|
|
|
|
|
2012-02-12 00:06:24 +01:00
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
|
2002-08-30 02:28:41 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
2007-07-25 06:19:09 +02:00
|
|
|
/* ----------
|
|
|
|
* exec_stmt_return_query Evaluate a query and add it to the
|
|
|
|
* list of tuples returned by the current
|
|
|
|
* SRF.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
exec_stmt_return_query(PLpgSQL_execstate *estate,
|
2007-11-15 23:25:18 +01:00
|
|
|
PLpgSQL_stmt_return_query *stmt)
|
2007-07-25 06:19:09 +02:00
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
Portal portal;
|
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 processed = 0;
|
2009-08-06 22:44:32 +02:00
|
|
|
TupleConversionMap *tupmap;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
2007-07-25 06:19:09 +02:00
|
|
|
|
|
|
|
if (!estate->retisset)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("cannot use RETURN QUERY in a non-SETOF function")));
|
|
|
|
|
|
|
|
if (estate->tuple_store == NULL)
|
|
|
|
exec_init_tuple_store(estate);
|
|
|
|
|
2008-05-03 02:11:36 +02:00
|
|
|
if (stmt->query != NULL)
|
|
|
|
{
|
|
|
|
/* static query */
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
exec_run_select(estate, stmt->query, 0, &portal);
|
2008-05-03 02:11:36 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* RETURN QUERY EXECUTE */
|
|
|
|
Assert(stmt->dynquery != NULL);
|
|
|
|
portal = exec_dynquery_with_params(estate, stmt->dynquery,
|
2015-09-16 21:38:47 +02:00
|
|
|
stmt->params, NULL,
|
2017-03-24 17:30:39 +01:00
|
|
|
0);
|
2008-05-03 02:11:36 +02:00
|
|
|
}
|
2007-07-25 06:19:09 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Use eval_mcontext for tuple conversion work */
|
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
|
|
|
|
2009-08-06 22:44:32 +02:00
|
|
|
tupmap = convert_tuples_by_position(portal->tupDesc,
|
|
|
|
estate->rettupdesc,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
gettext_noop("structure of query does not match function result type"));
|
2007-07-25 06:19:09 +02:00
|
|
|
|
|
|
|
while (true)
|
|
|
|
{
|
2016-06-10 00:02:36 +02:00
|
|
|
uint64 i;
|
2007-07-25 06:19:09 +02:00
|
|
|
|
|
|
|
SPI_cursor_fetch(portal, true, 50);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
|
|
|
|
/* SPI will have changed CurrentMemoryContext */
|
|
|
|
MemoryContextSwitchTo(get_eval_mcontext(estate));
|
|
|
|
|
2007-07-25 06:19:09 +02:00
|
|
|
if (SPI_processed == 0)
|
|
|
|
break;
|
|
|
|
|
|
|
|
for (i = 0; i < SPI_processed; i++)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
HeapTuple tuple = SPI_tuptable->vals[i];
|
|
|
|
|
2009-08-06 22:44:32 +02:00
|
|
|
if (tupmap)
|
|
|
|
tuple = do_convert_tuple(tuple, tupmap);
|
2007-07-25 06:19:09 +02:00
|
|
|
tuplestore_puttuple(estate->tuple_store, tuple);
|
2009-08-06 22:44:32 +02:00
|
|
|
if (tupmap)
|
|
|
|
heap_freetuple(tuple);
|
2009-02-05 16:25:49 +01:00
|
|
|
processed++;
|
2007-07-25 06:19:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
SPI_freetuptable(SPI_tuptable);
|
|
|
|
}
|
|
|
|
|
|
|
|
SPI_freetuptable(SPI_tuptable);
|
|
|
|
SPI_cursor_close(portal);
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
|
2009-02-05 16:25:49 +01:00
|
|
|
estate->eval_processed = processed;
|
|
|
|
exec_set_found(estate, processed != 0);
|
|
|
|
|
2007-07-25 06:19:09 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
2002-08-30 02:28:41 +02:00
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_init_tuple_store(PLpgSQL_execstate *estate)
|
2002-08-30 02:28:41 +02:00
|
|
|
{
|
|
|
|
ReturnSetInfo *rsi = estate->rsi;
|
|
|
|
MemoryContext oldcxt;
|
2009-12-29 18:40:59 +01:00
|
|
|
ResourceOwner oldowner;
|
2002-08-30 02:28:41 +02:00
|
|
|
|
2002-08-31 01:59:46 +02:00
|
|
|
/*
|
|
|
|
* Check caller can handle a set result in the way we want
|
|
|
|
*/
|
2002-08-30 02:28:41 +02:00
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
2002-08-31 01:59:46 +02:00
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0 ||
|
|
|
|
rsi->expectedDesc == NULL)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
2002-08-30 02:28:41 +02:00
|
|
|
|
2009-12-29 18:40:59 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Switch to the right memory context and resource owner for storing the
|
|
|
|
* tuplestore for return set. If we're within a subtransaction opened for
|
|
|
|
* an exception-block, for example, we must still create the tuplestore in
|
|
|
|
* the resource owner that was active when this function was entered, and
|
|
|
|
* not in the subtransaction resource owner.
|
2009-12-29 18:40:59 +01:00
|
|
|
*/
|
2002-08-30 02:28:41 +02:00
|
|
|
oldcxt = MemoryContextSwitchTo(estate->tuple_store_cxt);
|
2009-12-29 18:40:59 +01:00
|
|
|
oldowner = CurrentResourceOwner;
|
|
|
|
CurrentResourceOwner = estate->tuple_store_owner;
|
|
|
|
|
2008-10-29 01:00:39 +01:00
|
|
|
estate->tuple_store =
|
|
|
|
tuplestore_begin_heap(rsi->allowedModes & SFRM_Materialize_Random,
|
|
|
|
false, work_mem);
|
2009-12-29 18:40:59 +01:00
|
|
|
|
|
|
|
CurrentResourceOwner = oldowner;
|
2002-08-30 02:28:41 +02:00
|
|
|
MemoryContextSwitchTo(oldcxt);
|
2002-08-31 01:59:46 +02:00
|
|
|
|
|
|
|
estate->rettupdesc = rsi->expectedDesc;
|
2002-08-30 02:28:41 +02:00
|
|
|
}
|
|
|
|
|
2013-07-03 13:29:23 +02:00
|
|
|
#define SET_RAISE_OPTION_TEXT(opt, name) \
|
|
|
|
do { \
|
|
|
|
if (opt) \
|
|
|
|
ereport(ERROR, \
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR), \
|
|
|
|
errmsg("RAISE option already specified: %s", \
|
|
|
|
name))); \
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
opt = MemoryContextStrdup(stmt_mcontext, extval); \
|
2013-07-03 13:29:23 +02:00
|
|
|
} while (0)
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
2003-07-26 01:37:31 +02:00
|
|
|
* exec_stmt_raise Build a message and throw it with elog()
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_raise(PLpgSQL_execstate *estate, PLpgSQL_stmt_raise *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2008-05-14 00:10:30 +02:00
|
|
|
int err_code = 0;
|
|
|
|
char *condname = NULL;
|
|
|
|
char *err_message = NULL;
|
|
|
|
char *err_detail = NULL;
|
|
|
|
char *err_hint = NULL;
|
2013-07-03 13:29:23 +02:00
|
|
|
char *err_column = NULL;
|
|
|
|
char *err_constraint = NULL;
|
|
|
|
char *err_datatype = NULL;
|
|
|
|
char *err_table = NULL;
|
|
|
|
char *err_schema = NULL;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext stmt_mcontext;
|
2008-05-14 00:10:30 +02:00
|
|
|
ListCell *lc;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2008-05-14 00:10:30 +02:00
|
|
|
/* RAISE with no parameters: re-throw current exception */
|
|
|
|
if (stmt->condname == NULL && stmt->message == NULL &&
|
|
|
|
stmt->options == NIL)
|
2010-08-09 04:25:07 +02:00
|
|
|
{
|
|
|
|
if (estate->cur_error != NULL)
|
|
|
|
ReThrowError(estate->cur_error);
|
|
|
|
/* oops, we're not inside a handler */
|
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_STACKED_DIAGNOSTICS_ACCESSED_WITHOUT_ACTIVE_HANDLER),
|
|
|
|
errmsg("RAISE without parameters cannot be used outside an exception handler")));
|
2010-08-09 04:25:07 +02:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* We'll need to accumulate the various strings in stmt_mcontext */
|
|
|
|
stmt_mcontext = get_stmt_mcontext(estate);
|
|
|
|
|
2008-05-14 00:10:30 +02:00
|
|
|
if (stmt->condname)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2008-05-14 00:10:30 +02:00
|
|
|
err_code = plpgsql_recognize_err_condition(stmt->condname, true);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
condname = MemoryContextStrdup(stmt_mcontext, stmt->condname);
|
2008-05-14 00:10:30 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (stmt->message)
|
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
StringInfoData ds;
|
2008-05-14 00:10:30 +02:00
|
|
|
ListCell *current_param;
|
|
|
|
char *cp;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* build string in stmt_mcontext */
|
|
|
|
oldcontext = MemoryContextSwitchTo(stmt_mcontext);
|
2009-07-22 04:31:38 +02:00
|
|
|
initStringInfo(&ds);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2008-05-14 00:10:30 +02:00
|
|
|
current_param = list_head(stmt->params);
|
|
|
|
|
|
|
|
for (cp = stmt->message; *cp; cp++)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Occurrences of a single % are replaced by the next parameter's
|
|
|
|
* external representation. Double %'s are converted to one %.
|
|
|
|
*/
|
|
|
|
if (cp[0] == '%')
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2008-05-14 00:10:30 +02:00
|
|
|
Oid paramtypeid;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 paramtypmod;
|
2008-05-14 00:10:30 +02:00
|
|
|
Datum paramvalue;
|
|
|
|
bool paramisnull;
|
|
|
|
char *extval;
|
|
|
|
|
|
|
|
if (cp[1] == '%')
|
|
|
|
{
|
2009-07-22 04:31:38 +02:00
|
|
|
appendStringInfoChar(&ds, '%');
|
2008-05-14 00:10:30 +02:00
|
|
|
cp++;
|
|
|
|
continue;
|
|
|
|
}
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
|
2014-09-02 14:53:06 +02:00
|
|
|
/* should have been checked at compile time */
|
2008-05-14 00:10:30 +02:00
|
|
|
if (current_param == NULL)
|
2014-09-02 14:53:06 +02:00
|
|
|
elog(ERROR, "unexpected RAISE parameter list length");
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
|
2008-05-14 00:10:30 +02:00
|
|
|
paramvalue = exec_eval_expr(estate,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(PLpgSQL_expr *) lfirst(current_param),
|
2008-05-14 00:10:30 +02:00
|
|
|
¶misnull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
¶mtypeid,
|
|
|
|
¶mtypmod);
|
2005-06-14 08:43:15 +02:00
|
|
|
|
2008-05-14 00:10:30 +02:00
|
|
|
if (paramisnull)
|
|
|
|
extval = "<NULL>";
|
|
|
|
else
|
2012-02-12 00:06:24 +01:00
|
|
|
extval = convert_value_to_string(estate,
|
|
|
|
paramvalue,
|
|
|
|
paramtypeid);
|
2009-07-22 04:31:38 +02:00
|
|
|
appendStringInfoString(&ds, extval);
|
2008-05-14 00:10:30 +02:00
|
|
|
current_param = lnext(current_param);
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
}
|
2003-03-25 01:34:24 +01:00
|
|
|
else
|
2009-07-22 04:31:38 +02:00
|
|
|
appendStringInfoChar(&ds, cp[0]);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2014-09-02 14:53:06 +02:00
|
|
|
/* should have been checked at compile time */
|
2008-05-14 00:10:30 +02:00
|
|
|
if (current_param != NULL)
|
2014-09-02 14:53:06 +02:00
|
|
|
elog(ERROR, "unexpected RAISE parameter list length");
|
2008-05-14 00:10:30 +02:00
|
|
|
|
2009-07-22 04:31:38 +02:00
|
|
|
err_message = ds.data;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2008-05-14 00:10:30 +02:00
|
|
|
foreach(lc, stmt->options)
|
|
|
|
{
|
|
|
|
PLpgSQL_raise_option *opt = (PLpgSQL_raise_option *) lfirst(lc);
|
|
|
|
Datum optionvalue;
|
|
|
|
bool optionisnull;
|
|
|
|
Oid optiontypeid;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 optiontypmod;
|
2008-05-14 00:10:30 +02:00
|
|
|
char *extval;
|
|
|
|
|
|
|
|
optionvalue = exec_eval_expr(estate, opt->expr,
|
|
|
|
&optionisnull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
&optiontypeid,
|
|
|
|
&optiontypmod);
|
2008-05-14 00:10:30 +02:00
|
|
|
if (optionisnull)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("RAISE statement option cannot be null")));
|
2008-05-14 00:10:30 +02:00
|
|
|
|
2012-02-12 00:06:24 +01:00
|
|
|
extval = convert_value_to_string(estate, optionvalue, optiontypeid);
|
2008-05-14 00:10:30 +02:00
|
|
|
|
|
|
|
switch (opt->opt_type)
|
|
|
|
{
|
|
|
|
case PLPGSQL_RAISEOPTION_ERRCODE:
|
|
|
|
if (err_code)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("RAISE option already specified: %s",
|
|
|
|
"ERRCODE")));
|
|
|
|
err_code = plpgsql_recognize_err_condition(extval, true);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
condname = MemoryContextStrdup(stmt_mcontext, extval);
|
2008-05-14 00:10:30 +02:00
|
|
|
break;
|
|
|
|
case PLPGSQL_RAISEOPTION_MESSAGE:
|
2013-07-03 13:29:23 +02:00
|
|
|
SET_RAISE_OPTION_TEXT(err_message, "MESSAGE");
|
2008-05-14 00:10:30 +02:00
|
|
|
break;
|
|
|
|
case PLPGSQL_RAISEOPTION_DETAIL:
|
2013-07-03 13:29:23 +02:00
|
|
|
SET_RAISE_OPTION_TEXT(err_detail, "DETAIL");
|
2008-05-14 00:10:30 +02:00
|
|
|
break;
|
|
|
|
case PLPGSQL_RAISEOPTION_HINT:
|
2013-07-03 13:29:23 +02:00
|
|
|
SET_RAISE_OPTION_TEXT(err_hint, "HINT");
|
|
|
|
break;
|
|
|
|
case PLPGSQL_RAISEOPTION_COLUMN:
|
|
|
|
SET_RAISE_OPTION_TEXT(err_column, "COLUMN");
|
|
|
|
break;
|
|
|
|
case PLPGSQL_RAISEOPTION_CONSTRAINT:
|
|
|
|
SET_RAISE_OPTION_TEXT(err_constraint, "CONSTRAINT");
|
|
|
|
break;
|
|
|
|
case PLPGSQL_RAISEOPTION_DATATYPE:
|
|
|
|
SET_RAISE_OPTION_TEXT(err_datatype, "DATATYPE");
|
|
|
|
break;
|
|
|
|
case PLPGSQL_RAISEOPTION_TABLE:
|
|
|
|
SET_RAISE_OPTION_TEXT(err_table, "TABLE");
|
|
|
|
break;
|
|
|
|
case PLPGSQL_RAISEOPTION_SCHEMA:
|
|
|
|
SET_RAISE_OPTION_TEXT(err_schema, "SCHEMA");
|
2008-05-14 00:10:30 +02:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized raise option: %d", opt->opt_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Default code if nothing specified */
|
|
|
|
if (err_code == 0 && stmt->elog_level >= ERROR)
|
|
|
|
err_code = ERRCODE_RAISE_EXCEPTION;
|
|
|
|
|
|
|
|
/* Default error message if nothing specified */
|
|
|
|
if (err_message == NULL)
|
|
|
|
{
|
|
|
|
if (condname)
|
|
|
|
{
|
|
|
|
err_message = condname;
|
|
|
|
condname = NULL;
|
|
|
|
}
|
|
|
|
else
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
err_message = MemoryContextStrdup(stmt_mcontext,
|
|
|
|
unpack_sql_state(err_code));
|
2008-05-14 00:10:30 +02:00
|
|
|
}
|
This patch changes makes some significant changes to how compilation
and parsing work in PL/PgSQL:
- memory management is now done via palloc(). The compiled representation
of each function now has its own memory context. Therefore, the storage
consumed by a function can be reclaimed via MemoryContextDelete().
During compilation, the CurrentMemoryContext is the function's memory
context. This means that a palloc() is sufficient to allocate memory
that will have the same lifetime as the function itself. As a result,
code invoked during compilation should be careful to pfree() temporary
allocations to avoid leaking memory. Since a lot of the code in the
backend is not careful about releasing palloc'ed memory, that means
we should switch into a temporary memory context before invoking
backend functions. A temporary context appropriate for such allocations
is `compile_tmp_cxt'.
- The ability to use palloc() allows us to simply a lot of the code in
the parser. Rather than representing lists of elements via ad hoc
linked lists or arrays, we can use the List type. Rather than doing
malloc followed by memset(0), we can just use palloc0().
- We now check that the user has supplied the right number of parameters
to a RAISE statement. Supplying either too few or too many results in
an error (at runtime).
- PL/PgSQL's parser needs to accept arbitrary SQL statements. Since we
do not want to duplicate the SQL grammar in the PL/PgSQL grammar, this
means we need to be quite lax in what the PL/PgSQL grammar considers
a "SQL statement". This can lead to misleading behavior if there is a
syntax error in the function definition, since we assume a malformed
PL/PgSQL construct is a SQL statement. Furthermore, these errors were
only detected at runtime (when we tried to execute the alleged "SQL
statement" via SPI).
To rectify this, the patch changes the parser to invoke the main SQL
parser when it sees a string it believes to be a SQL expression. This
means that synctically-invalid SQL will be rejected during the
compilation of the PL/PgSQL function. This is only done when compiling
for "validation" purposes (i.e. at CREATE FUNCTION time), so it should
not impose a runtime overhead.
- Fixes for the various buffer overruns I've patched in stable branches
in the past few weeks. I've rewritten code where I thought it was
warranted (unlike the patches applied to older branches, which were
minimally invasive).
- Various other minor changes and cleanups.
- Updates to the regression tests.
2005-02-22 08:18:27 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-04-24 23:16:45 +02:00
|
|
|
* Throw the error (may or may not come back)
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
2003-04-24 23:16:45 +02:00
|
|
|
ereport(stmt->elog_level,
|
2008-05-14 00:10:30 +02:00
|
|
|
(err_code ? errcode(err_code) : 0,
|
|
|
|
errmsg_internal("%s", err_message),
|
2011-07-16 20:21:12 +02:00
|
|
|
(err_detail != NULL) ? errdetail_internal("%s", err_detail) : 0,
|
2013-07-03 13:29:23 +02:00
|
|
|
(err_hint != NULL) ? errhint("%s", err_hint) : 0,
|
|
|
|
(err_column != NULL) ?
|
|
|
|
err_generic_string(PG_DIAG_COLUMN_NAME, err_column) : 0,
|
|
|
|
(err_constraint != NULL) ?
|
|
|
|
err_generic_string(PG_DIAG_CONSTRAINT_NAME, err_constraint) : 0,
|
|
|
|
(err_datatype != NULL) ?
|
|
|
|
err_generic_string(PG_DIAG_DATATYPE_NAME, err_datatype) : 0,
|
|
|
|
(err_table != NULL) ?
|
|
|
|
err_generic_string(PG_DIAG_TABLE_NAME, err_table) : 0,
|
|
|
|
(err_schema != NULL) ?
|
|
|
|
err_generic_string(PG_DIAG_SCHEMA_NAME, err_schema) : 0));
|
2003-04-24 23:16:45 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Clean up transient strings */
|
|
|
|
MemoryContextReset(stmt_mcontext);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2015-03-26 00:05:20 +01:00
|
|
|
/* ----------
|
|
|
|
* exec_stmt_assert Assert statement
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
exec_stmt_assert(PLpgSQL_execstate *estate, PLpgSQL_stmt_assert *stmt)
|
|
|
|
{
|
|
|
|
bool value;
|
|
|
|
bool isnull;
|
|
|
|
|
|
|
|
/* do nothing when asserts are not enabled */
|
|
|
|
if (!plpgsql_check_asserts)
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
|
|
|
|
value = exec_eval_boolean(estate, stmt->cond, &isnull);
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
|
|
|
|
if (isnull || !value)
|
|
|
|
{
|
|
|
|
char *message = NULL;
|
|
|
|
|
|
|
|
if (stmt->message != NULL)
|
|
|
|
{
|
|
|
|
Datum val;
|
|
|
|
Oid typeid;
|
|
|
|
int32 typmod;
|
|
|
|
|
|
|
|
val = exec_eval_expr(estate, stmt->message,
|
|
|
|
&isnull, &typeid, &typmod);
|
|
|
|
if (!isnull)
|
|
|
|
message = convert_value_to_string(estate, val, typeid);
|
|
|
|
/* we mustn't do exec_eval_cleanup here */
|
|
|
|
}
|
|
|
|
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_ASSERT_FAILURE),
|
|
|
|
message ? errmsg_internal("%s", message) :
|
|
|
|
errmsg("assertion failed")));
|
|
|
|
}
|
|
|
|
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
/* ----------
|
2002-08-30 02:28:41 +02:00
|
|
|
* Initialize a mostly empty execution state
|
2001-08-02 23:31:23 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
plpgsql_estate_setup(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_function *func,
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
ReturnSetInfo *rsi,
|
|
|
|
EState *simple_eval_estate)
|
2001-08-02 23:31:23 +02:00
|
|
|
{
|
2015-08-15 18:00:36 +02:00
|
|
|
HASHCTL ctl;
|
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
/* this link will be restored at exit from plpgsql_call_handler */
|
|
|
|
func->cur_estate = estate;
|
|
|
|
|
|
|
|
estate->func = func;
|
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
estate->retval = (Datum) 0;
|
|
|
|
estate->retisnull = true;
|
|
|
|
estate->rettype = InvalidOid;
|
2002-08-30 02:28:41 +02:00
|
|
|
|
|
|
|
estate->fn_rettype = func->fn_rettype;
|
2001-08-02 23:31:23 +02:00
|
|
|
estate->retistuple = func->fn_retistuple;
|
|
|
|
estate->retisset = func->fn_retset;
|
2002-08-30 02:28:41 +02:00
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
estate->readonly_func = func->fn_readonly;
|
|
|
|
|
2002-08-30 02:28:41 +02:00
|
|
|
estate->rettupdesc = NULL;
|
2001-08-02 23:31:23 +02:00
|
|
|
estate->exitlabel = NULL;
|
2010-08-09 04:25:07 +02:00
|
|
|
estate->cur_error = NULL;
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2002-08-30 02:28:41 +02:00
|
|
|
estate->tuple_store = NULL;
|
2009-12-29 18:40:59 +01:00
|
|
|
if (rsi)
|
|
|
|
{
|
|
|
|
estate->tuple_store_cxt = rsi->econtext->ecxt_per_query_memory;
|
|
|
|
estate->tuple_store_owner = CurrentResourceOwner;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
estate->tuple_store_cxt = NULL;
|
|
|
|
estate->tuple_store_owner = NULL;
|
|
|
|
}
|
2002-08-30 02:28:41 +02:00
|
|
|
estate->rsi = rsi;
|
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
estate->found_varno = func->found_varno;
|
|
|
|
estate->ndatums = func->ndatums;
|
|
|
|
estate->datums = palloc(sizeof(PLpgSQL_datum *) * estate->ndatums);
|
|
|
|
/* caller is expected to fill the datums array */
|
|
|
|
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
/* initialize ParamListInfo with one entry per datum, all invalid */
|
|
|
|
estate->paramLI = (ParamListInfo)
|
|
|
|
palloc0(offsetof(ParamListInfoData, params) +
|
|
|
|
estate->ndatums * sizeof(ParamExternData));
|
|
|
|
estate->paramLI->paramFetch = plpgsql_param_fetch;
|
|
|
|
estate->paramLI->paramFetchArg = (void *) estate;
|
|
|
|
estate->paramLI->parserSetup = (ParserSetupHook) plpgsql_parser_setup;
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
estate->paramLI->parserSetupArg = NULL; /* filled during use */
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
estate->paramLI->numParams = estate->ndatums;
|
Fix problems with ParamListInfo serialization mechanism.
Commit d1b7c1ffe72e86932b5395f29e006c3f503bc53d introduced a mechanism
for serializing a ParamListInfo structure to be passed to a parallel
worker. However, this mechanism failed to handle external expanded
values, as pointed out by Noah Misch. Repair.
Moreover, plpgsql_param_fetch requires adjustment because the
serialization mechanism needs it to skip evaluating unused parameters
just as we would do when it is called from copyParamList, but params
== estate->paramLI in that case. To fix, make the bms_is_member test
in that function unconditional.
Finally, have setup_param_list set a new ParamListInfo field,
paramMask, to the parameters actually used in the expression, so that
we don't try to fetch those that are not needed when serializing a
parameter list. This isn't necessary for correctness, but it makes
the performance of the parallel executor code comparable to what we
do for cases involving cursors.
Design suggestions and extensive review by Noah Misch. Patch by me.
2015-11-03 00:11:29 +01:00
|
|
|
estate->paramLI->paramMask = NULL;
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
estate->params_dirty = false;
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
|
2015-08-15 18:00:36 +02:00
|
|
|
/* set up for use of appropriate simple-expression EState and cast hash */
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
if (simple_eval_estate)
|
2015-08-15 18:00:36 +02:00
|
|
|
{
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
estate->simple_eval_estate = simple_eval_estate;
|
2015-08-15 18:00:36 +02:00
|
|
|
/* Private cast hash just lives in function's main context */
|
|
|
|
memset(&ctl, 0, sizeof(ctl));
|
|
|
|
ctl.keysize = sizeof(plpgsql_CastHashKey);
|
|
|
|
ctl.entrysize = sizeof(plpgsql_CastHashEntry);
|
|
|
|
ctl.hcxt = CurrentMemoryContext;
|
|
|
|
estate->cast_hash = hash_create("PLpgSQL private cast cache",
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
16, /* start small and extend */
|
2015-08-15 18:00:36 +02:00
|
|
|
&ctl,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
|
2015-08-15 18:00:36 +02:00
|
|
|
estate->cast_hash_context = CurrentMemoryContext;
|
|
|
|
}
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
else
|
2015-08-15 18:00:36 +02:00
|
|
|
{
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
estate->simple_eval_estate = shared_simple_eval_estate;
|
2015-08-15 18:00:36 +02:00
|
|
|
/* Create the session-wide cast-info hash table if we didn't already */
|
|
|
|
if (shared_cast_hash == NULL)
|
|
|
|
{
|
|
|
|
shared_cast_context = AllocSetContextCreate(TopMemoryContext,
|
|
|
|
"PLpgSQL cast info",
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
ALLOCSET_DEFAULT_SIZES);
|
2015-08-15 18:00:36 +02:00
|
|
|
memset(&ctl, 0, sizeof(ctl));
|
|
|
|
ctl.keysize = sizeof(plpgsql_CastHashKey);
|
|
|
|
ctl.entrysize = sizeof(plpgsql_CastHashEntry);
|
|
|
|
ctl.hcxt = shared_cast_context;
|
|
|
|
shared_cast_hash = hash_create("PLpgSQL cast cache",
|
|
|
|
16, /* start small and extend */
|
|
|
|
&ctl,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
|
2015-08-15 18:00:36 +02:00
|
|
|
}
|
|
|
|
estate->cast_hash = shared_cast_hash;
|
|
|
|
estate->cast_hash_context = shared_cast_context;
|
|
|
|
}
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* We start with no stmt_mcontext; one will be created only if needed.
|
|
|
|
* That context will be a direct child of the function's main execution
|
|
|
|
* context. Additional stmt_mcontexts might be created as children of it.
|
|
|
|
*/
|
|
|
|
estate->stmt_mcontext = NULL;
|
|
|
|
estate->stmt_mcontext_parent = CurrentMemoryContext;
|
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
estate->eval_tuptable = NULL;
|
|
|
|
estate->eval_processed = 0;
|
|
|
|
estate->eval_lastoid = InvalidOid;
|
2009-11-04 23:26:08 +01:00
|
|
|
estate->eval_econtext = NULL;
|
2003-04-24 23:16:45 +02:00
|
|
|
|
|
|
|
estate->err_stmt = NULL;
|
|
|
|
estate->err_text = NULL;
|
2005-06-21 00:51:29 +02:00
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
estate->plugin_info = NULL;
|
|
|
|
|
2005-06-21 00:51:29 +02:00
|
|
|
/*
|
2007-01-28 17:15:49 +01:00
|
|
|
* Create an EState and ExprContext for evaluation of simple expressions.
|
2005-06-21 00:51:29 +02:00
|
|
|
*/
|
2007-01-28 17:15:49 +01:00
|
|
|
plpgsql_create_econtext(estate);
|
2006-08-15 21:01:17 +02:00
|
|
|
|
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* Let the plugin see this function before we initialize any local
|
|
|
|
* PL/pgSQL variables - note that we also give the plugin a few function
|
|
|
|
* pointers so it can call back into PL/pgSQL for doing things like
|
|
|
|
* variable assignments and stack traces
|
2006-08-15 21:01:17 +02:00
|
|
|
*/
|
2016-03-03 10:45:59 +01:00
|
|
|
if (*plpgsql_plugin_ptr)
|
2006-08-15 21:01:17 +02:00
|
|
|
{
|
2016-03-03 10:45:59 +01:00
|
|
|
(*plpgsql_plugin_ptr)->error_callback = plpgsql_exec_error_callback;
|
|
|
|
(*plpgsql_plugin_ptr)->assign_expr = exec_assign_expr;
|
2006-08-15 21:01:17 +02:00
|
|
|
|
2016-03-03 10:45:59 +01:00
|
|
|
if ((*plpgsql_plugin_ptr)->func_setup)
|
|
|
|
((*plpgsql_plugin_ptr)->func_setup) (estate, func);
|
2006-08-15 21:01:17 +02:00
|
|
|
}
|
2001-08-02 23:31:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Release temporary memory used by expression/subselect evaluation
|
|
|
|
*
|
|
|
|
* NB: the result of the evaluation is no longer valid after this is done,
|
|
|
|
* unless it is a pass-by-value datatype.
|
2010-08-09 20:50:11 +02:00
|
|
|
*
|
|
|
|
* NB: if you change this code, see also the hacks in exec_assign_value's
|
2015-03-14 22:07:01 +01:00
|
|
|
* PLPGSQL_DTYPE_ARRAYELEM case for partial cleanup after subscript evals.
|
2001-08-02 23:31:23 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_eval_cleanup(PLpgSQL_execstate *estate)
|
2001-08-02 23:31:23 +02:00
|
|
|
{
|
2004-09-13 22:10:13 +02:00
|
|
|
/* Clear result of a full SPI_execute */
|
2001-08-02 23:31:23 +02:00
|
|
|
if (estate->eval_tuptable != NULL)
|
|
|
|
SPI_freetuptable(estate->eval_tuptable);
|
|
|
|
estate->eval_tuptable = NULL;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/*
|
|
|
|
* Clear result of exec_eval_simple_expr (but keep the econtext). This
|
|
|
|
* also clears any short-lived allocations done via get_eval_mcontext.
|
|
|
|
*/
|
2001-08-02 23:31:23 +02:00
|
|
|
if (estate->eval_econtext != NULL)
|
2003-09-29 01:37:45 +02:00
|
|
|
ResetExprContext(estate->eval_econtext);
|
2001-08-02 23:31:23 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-01-27 17:15:22 +01:00
|
|
|
/* ----------
|
|
|
|
* Generate a prepared plan
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_prepare_plan(PLpgSQL_execstate *estate,
|
2007-04-16 19:21:24 +02:00
|
|
|
PLpgSQL_expr *expr, int cursorOptions)
|
1999-01-27 17:15:22 +01:00
|
|
|
{
|
2007-03-16 00:12:07 +01:00
|
|
|
SPIPlanPtr plan;
|
1999-01-27 17:15:22 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* The grammar can't conveniently set expr->func while building the parse
|
|
|
|
* tree, so make sure it's set before parser hooks need it.
|
1999-01-27 17:15:22 +01:00
|
|
|
*/
|
2009-11-04 23:26:08 +01:00
|
|
|
expr->func = estate->func;
|
1999-01-27 17:15:22 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1999-01-27 17:15:22 +01:00
|
|
|
* Generate and save the plan
|
|
|
|
*/
|
2009-11-04 23:26:08 +01:00
|
|
|
plan = SPI_prepare_params(expr->query,
|
|
|
|
(ParserSetupHook) plpgsql_parser_setup,
|
|
|
|
(void *) expr,
|
2007-04-16 19:21:24 +02:00
|
|
|
cursorOptions);
|
1999-01-27 17:15:22 +01:00
|
|
|
if (plan == NULL)
|
2004-08-13 20:47:56 +02:00
|
|
|
{
|
|
|
|
/* Some SPI errors deserve specific error messages */
|
|
|
|
switch (SPI_result)
|
|
|
|
{
|
|
|
|
case SPI_ERROR_COPY:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("cannot COPY to/from client in PL/pgSQL")));
|
2004-08-13 20:47:56 +02:00
|
|
|
case SPI_ERROR_TRANSACTION:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("cannot begin/end transactions in PL/pgSQL"),
|
2004-08-13 20:47:56 +02:00
|
|
|
errhint("Use a BEGIN block with an EXCEPTION clause instead.")));
|
|
|
|
default:
|
2009-11-04 23:26:08 +01:00
|
|
|
elog(ERROR, "SPI_prepare_params failed for \"%s\": %s",
|
2004-08-13 20:47:56 +02:00
|
|
|
expr->query, SPI_result_code_string(SPI_result));
|
|
|
|
}
|
|
|
|
}
|
2011-09-16 06:42:53 +02:00
|
|
|
SPI_keepplan(plan);
|
|
|
|
expr->plan = plan;
|
|
|
|
|
|
|
|
/* Check to see if it's a simple expression */
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
exec_simple_check_plan(estate, expr);
|
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
|
|
|
|
|
|
|
/*
|
|
|
|
* Mark expression as not using a read-write param. exec_assign_value has
|
|
|
|
* to take steps to override this if appropriate; that seems cleaner than
|
|
|
|
* adding parameters to all other callers.
|
|
|
|
*/
|
|
|
|
expr->rwparam = -1;
|
1999-01-27 17:15:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
2006-08-14 23:14:42 +02:00
|
|
|
* exec_stmt_execsql Execute an SQL statement (possibly with INTO).
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
*
|
|
|
|
* Note: some callers rely on this not touching stmt_mcontext. If it ever
|
|
|
|
* needs to use that, fix those callers to push/pop stmt_mcontext.
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_execsql(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_execsql *stmt)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2009-11-04 23:26:08 +01:00
|
|
|
ParamListInfo paramLI;
|
2006-08-14 23:14:42 +02:00
|
|
|
long tcount;
|
1998-09-01 06:40:42 +02:00
|
|
|
int rc;
|
|
|
|
PLpgSQL_expr *expr = stmt->sqlstmt;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* On the first call for this statement generate the plan, and detect
|
|
|
|
* whether the statement is INSERT/UPDATE/DELETE
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
if (expr->plan == NULL)
|
2006-08-14 23:14:42 +02:00
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK);
|
2006-08-14 23:14:42 +02:00
|
|
|
stmt->mod_stmt = false;
|
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
|
|
|
foreach(l, SPI_plan_get_plan_sources(expr->plan))
|
2006-08-14 23:14:42 +02:00
|
|
|
{
|
2007-03-16 00:12:07 +01:00
|
|
|
CachedPlanSource *plansource = (CachedPlanSource *) lfirst(l);
|
2006-08-14 23:14:42 +02:00
|
|
|
ListCell *l2;
|
|
|
|
|
2011-09-16 06:42:53 +02:00
|
|
|
foreach(l2, plansource->query_list)
|
2006-08-14 23:14:42 +02:00
|
|
|
{
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
Query *q = lfirst_node(Query, l2);
|
2006-08-14 23:14:42 +02:00
|
|
|
|
2011-09-16 06:42:53 +02:00
|
|
|
if (q->canSetTag)
|
2006-08-14 23:14:42 +02:00
|
|
|
{
|
2011-09-16 06:42:53 +02:00
|
|
|
if (q->commandType == CMD_INSERT ||
|
|
|
|
q->commandType == CMD_UPDATE ||
|
|
|
|
q->commandType == CMD_DELETE)
|
2006-08-14 23:14:42 +02:00
|
|
|
stmt->mod_stmt = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2011-09-16 18:31:23 +02:00
|
|
|
/*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* Set up ParamListInfo to pass to executor
|
2011-09-16 18:31:23 +02:00
|
|
|
*/
|
|
|
|
paramLI = setup_param_list(estate, expr);
|
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* If we have INTO, then we only need one row back ... but if we have INTO
|
|
|
|
* STRICT, ask for two rows, so that we can verify the statement returns
|
|
|
|
* only one. INSERT/UPDATE/DELETE are always treated strictly. Without
|
|
|
|
* INTO, just run the statement to completion (tcount = 0).
|
2006-08-14 23:14:42 +02:00
|
|
|
*
|
2006-10-04 02:30:14 +02:00
|
|
|
* We could just ask for two rows always when using INTO, but there are
|
|
|
|
* some cases where demanding the extra row costs significant time, eg by
|
|
|
|
* forcing completion of a sequential scan. So don't do it unless we need
|
|
|
|
* to enforce strictness.
|
2006-08-14 23:14:42 +02:00
|
|
|
*/
|
|
|
|
if (stmt->into)
|
|
|
|
{
|
|
|
|
if (stmt->strict || stmt->mod_stmt)
|
|
|
|
tcount = 2;
|
|
|
|
else
|
|
|
|
tcount = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
tcount = 0;
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1998-09-01 06:40:42 +02:00
|
|
|
* Execute the plan
|
|
|
|
*/
|
2009-11-04 23:26:08 +01:00
|
|
|
rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
|
|
|
|
estate->readonly_func, tcount);
|
2006-08-14 23:14:42 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for error, and set FOUND if appropriate (for historical reasons
|
2014-05-06 18:12:18 +02:00
|
|
|
* we set FOUND only for certain query types). Also Assert that we
|
2009-01-21 12:02:40 +01:00
|
|
|
* identified the statement type the same as SPI did.
|
2006-08-14 23:14:42 +02:00
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
switch (rc)
|
|
|
|
{
|
2006-08-14 23:14:42 +02:00
|
|
|
case SPI_OK_SELECT:
|
2009-01-21 12:02:40 +01:00
|
|
|
Assert(!stmt->mod_stmt);
|
2006-08-14 23:14:42 +02:00
|
|
|
exec_set_found(estate, (SPI_processed != 0));
|
2002-08-20 07:28:24 +02:00
|
|
|
break;
|
|
|
|
|
2002-08-29 06:12:03 +02:00
|
|
|
case SPI_OK_INSERT:
|
|
|
|
case SPI_OK_UPDATE:
|
2006-08-14 23:14:42 +02:00
|
|
|
case SPI_OK_DELETE:
|
2006-08-28 01:47:58 +02:00
|
|
|
case SPI_OK_INSERT_RETURNING:
|
|
|
|
case SPI_OK_UPDATE_RETURNING:
|
|
|
|
case SPI_OK_DELETE_RETURNING:
|
2009-01-21 12:02:40 +01:00
|
|
|
Assert(stmt->mod_stmt);
|
2006-08-14 23:14:42 +02:00
|
|
|
exec_set_found(estate, (SPI_processed != 0));
|
|
|
|
break;
|
2002-09-04 22:31:48 +02:00
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
case SPI_OK_SELINTO:
|
|
|
|
case SPI_OK_UTILITY:
|
2009-01-21 12:02:40 +01:00
|
|
|
Assert(!stmt->mod_stmt);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case SPI_OK_REWRITTEN:
|
|
|
|
Assert(!stmt->mod_stmt);
|
2009-06-11 16:49:15 +02:00
|
|
|
|
2009-01-21 12:02:40 +01:00
|
|
|
/*
|
|
|
|
* The command was rewritten into another kind of command. It's
|
|
|
|
* not clear what FOUND would mean in that case (and SPI doesn't
|
|
|
|
* return the row count either), so just set it to false.
|
|
|
|
*/
|
|
|
|
exec_set_found(estate, false);
|
1998-09-01 06:40:42 +02:00
|
|
|
break;
|
|
|
|
|
2010-10-29 10:41:28 +02:00
|
|
|
/* Some SPI errors deserve specific error messages */
|
|
|
|
case SPI_ERROR_COPY:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot COPY to/from client in PL/pgSQL")));
|
|
|
|
case SPI_ERROR_TRANSACTION:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot begin/end transactions in PL/pgSQL"),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errhint("Use a BEGIN block with an EXCEPTION clause instead.")));
|
2010-10-29 10:41:28 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
default:
|
2009-11-04 23:26:08 +01:00
|
|
|
elog(ERROR, "SPI_execute_plan_with_paramlist failed executing query \"%s\": %s",
|
2004-07-31 22:55:45 +02:00
|
|
|
expr->query, SPI_result_code_string(rc));
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
/* All variants should save result info for GET DIAGNOSTICS */
|
2001-08-02 23:31:23 +02:00
|
|
|
estate->eval_processed = SPI_processed;
|
|
|
|
estate->eval_lastoid = SPI_lastoid;
|
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
/* Process INTO if present */
|
|
|
|
if (stmt->into)
|
|
|
|
{
|
|
|
|
SPITupleTable *tuptab = SPI_tuptable;
|
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 n = SPI_processed;
|
2006-08-14 23:14:42 +02:00
|
|
|
PLpgSQL_rec *rec = NULL;
|
|
|
|
PLpgSQL_row *row = NULL;
|
|
|
|
|
|
|
|
/* If the statement did not return a tuple table, complain */
|
|
|
|
if (tuptab == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("INTO used with a command that cannot return data")));
|
2006-08-14 23:14:42 +02:00
|
|
|
|
|
|
|
/* Determine if we assign to a record or a row */
|
|
|
|
if (stmt->rec != NULL)
|
2008-11-05 01:07:54 +01:00
|
|
|
rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->dno]);
|
2006-08-14 23:14:42 +02:00
|
|
|
else if (stmt->row != NULL)
|
2008-11-05 01:07:54 +01:00
|
|
|
row = (PLpgSQL_row *) (estate->datums[stmt->row->dno]);
|
2006-08-14 23:14:42 +02:00
|
|
|
else
|
|
|
|
elog(ERROR, "unsupported target");
|
|
|
|
|
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* If SELECT ... INTO specified STRICT, and the query didn't find
|
|
|
|
* exactly one row, throw an error. If STRICT was not specified, then
|
|
|
|
* allow the query to find any number of rows.
|
2006-08-14 23:14:42 +02:00
|
|
|
*/
|
|
|
|
if (n == 0)
|
|
|
|
{
|
|
|
|
if (stmt->strict)
|
2013-10-07 21:38:49 +02:00
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
char *errdetail;
|
2013-10-07 21:38:49 +02:00
|
|
|
|
|
|
|
if (estate->func->print_strict_params)
|
|
|
|
errdetail = format_expr_params(estate, expr);
|
|
|
|
else
|
|
|
|
errdetail = NULL;
|
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NO_DATA_FOUND),
|
2013-10-07 21:38:49 +02:00
|
|
|
errmsg("query returned no rows"),
|
2013-11-10 15:20:52 +01:00
|
|
|
errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
|
2013-10-07 21:38:49 +02:00
|
|
|
}
|
2006-08-14 23:14:42 +02:00
|
|
|
/* set the target to NULL(s) */
|
|
|
|
exec_move_row(estate, rec, row, NULL, tuptab->tupdesc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (n > 1 && (stmt->strict || stmt->mod_stmt))
|
2013-10-07 21:38:49 +02:00
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
char *errdetail;
|
2013-10-07 21:38:49 +02:00
|
|
|
|
|
|
|
if (estate->func->print_strict_params)
|
|
|
|
errdetail = format_expr_params(estate, expr);
|
|
|
|
else
|
|
|
|
errdetail = NULL;
|
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_TOO_MANY_ROWS),
|
2013-10-07 21:38:49 +02:00
|
|
|
errmsg("query returned more than one row"),
|
2013-11-10 15:20:52 +01:00
|
|
|
errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
|
2013-10-07 21:38:49 +02:00
|
|
|
}
|
2006-08-14 23:14:42 +02:00
|
|
|
/* Put the first result row into the target */
|
|
|
|
exec_move_row(estate, rec, row, tuptab->vals[0], tuptab->tupdesc);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Clean up */
|
2012-02-12 00:06:24 +01:00
|
|
|
exec_eval_cleanup(estate);
|
2006-08-14 23:14:42 +02:00
|
|
|
SPI_freetuptable(SPI_tuptable);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* If the statement returned a tuple table, complain */
|
|
|
|
if (SPI_tuptable != NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("query has no destination for result data"),
|
|
|
|
(rc == SPI_OK_SELECT) ? errhint("If you want to discard the results of a SELECT, use PERFORM instead.") : 0));
|
|
|
|
}
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-08-31 15:26:16 +02:00
|
|
|
/* ----------
|
2006-08-14 23:14:42 +02:00
|
|
|
* exec_stmt_dynexecute Execute a dynamic SQL query
|
|
|
|
* (possibly with INTO).
|
2000-08-31 15:26:16 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_dynexecute(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_stmt_dynexecute *stmt)
|
2000-08-31 15:26:16 +02:00
|
|
|
{
|
|
|
|
Datum query;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
bool isnull;
|
2000-08-31 15:26:16 +02:00
|
|
|
Oid restype;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 restypmod;
|
2000-08-31 15:26:16 +02:00
|
|
|
char *querystr;
|
2001-01-04 03:38:02 +01:00
|
|
|
int exec_res;
|
2013-10-07 21:38:49 +02:00
|
|
|
PreparedParamsData *ppd = NULL;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
|
2000-08-31 15:26:16 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* First we evaluate the string expression after the EXECUTE keyword. Its
|
|
|
|
* result is the querystring we have to execute.
|
2000-08-31 15:26:16 +02:00
|
|
|
*/
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
query = exec_eval_expr(estate, stmt->query, &isnull, &restype, &restypmod);
|
2000-08-31 15:26:16 +02:00
|
|
|
if (isnull)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("query string argument of EXECUTE is null")));
|
2000-08-31 15:26:16 +02:00
|
|
|
|
2003-10-01 23:47:42 +02:00
|
|
|
/* Get the C-String representation */
|
2012-02-12 00:06:24 +01:00
|
|
|
querystr = convert_value_to_string(estate, query, restype);
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* copy it into the stmt_mcontext before we clean up */
|
|
|
|
querystr = MemoryContextStrdup(stmt_mcontext, querystr);
|
2000-08-31 15:26:16 +02:00
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(estate);
|
2000-11-16 23:30:52 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2008-04-01 05:51:09 +02:00
|
|
|
* Execute the query without preparing a saved plan.
|
2000-08-31 15:26:16 +02:00
|
|
|
*/
|
2008-04-01 05:51:09 +02:00
|
|
|
if (stmt->params)
|
|
|
|
{
|
|
|
|
ppd = exec_eval_using_params(estate, stmt->params);
|
|
|
|
exec_res = SPI_execute_with_args(querystr,
|
|
|
|
ppd->nargs, ppd->types,
|
|
|
|
ppd->values, ppd->nulls,
|
|
|
|
estate->readonly_func, 0);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
exec_res = SPI_execute(querystr, estate->readonly_func, 0);
|
2005-06-07 04:47:23 +02:00
|
|
|
|
2001-01-04 03:38:02 +01:00
|
|
|
switch (exec_res)
|
2000-08-31 15:26:16 +02:00
|
|
|
{
|
2001-01-04 03:38:02 +01:00
|
|
|
case SPI_OK_SELECT:
|
2000-08-31 15:26:16 +02:00
|
|
|
case SPI_OK_INSERT:
|
|
|
|
case SPI_OK_UPDATE:
|
|
|
|
case SPI_OK_DELETE:
|
2006-08-28 01:47:58 +02:00
|
|
|
case SPI_OK_INSERT_RETURNING:
|
|
|
|
case SPI_OK_UPDATE_RETURNING:
|
|
|
|
case SPI_OK_DELETE_RETURNING:
|
2001-01-04 03:38:02 +01:00
|
|
|
case SPI_OK_UTILITY:
|
2009-01-21 12:13:14 +01:00
|
|
|
case SPI_OK_REWRITTEN:
|
2000-08-31 15:26:16 +02:00
|
|
|
break;
|
|
|
|
|
2001-01-04 03:38:02 +01:00
|
|
|
case 0:
|
2001-03-22 05:01:46 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Also allow a zero return, which implies the querystring
|
2001-01-04 03:38:02 +01:00
|
|
|
* contained no commands.
|
|
|
|
*/
|
2000-08-31 15:26:16 +02:00
|
|
|
break;
|
|
|
|
|
2001-02-09 01:14:26 +01:00
|
|
|
case SPI_OK_SELINTO:
|
2001-03-22 05:01:46 +01:00
|
|
|
|
2001-02-09 01:14:26 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We want to disallow SELECT INTO for now, because its behavior
|
|
|
|
* is not consistent with SELECT INTO in a normal plpgsql context.
|
|
|
|
* (We need to reimplement EXECUTE to parse the string as a
|
Restructure SELECT INTO's parsetree representation into CreateTableAsStmt.
Making this operation look like a utility statement seems generally a good
idea, and particularly so in light of the desire to provide command
triggers for utility statements. The original choice of representing it as
SELECT with an IntoClause appendage had metastasized into rather a lot of
places, unfortunately, so that this patch is a great deal more complicated
than one might at first expect.
In particular, keeping EXPLAIN working for SELECT INTO and CREATE TABLE AS
subcommands required restructuring some EXPLAIN-related APIs. Add-on code
that calls ExplainOnePlan or ExplainOneUtility, or uses
ExplainOneQuery_hook, will need adjustment.
Also, the cases PREPARE ... SELECT INTO and CREATE RULE ... SELECT INTO,
which formerly were accepted though undocumented, are no longer accepted.
The PREPARE case can be replaced with use of CREATE TABLE AS EXECUTE.
The CREATE RULE case doesn't seem to have much real-world use (since the
rule would work only once before failing with "table already exists"),
so we'll not bother with that one.
Both SELECT INTO and CREATE TABLE AS still return a command tag of
"SELECT nnnn". There was some discussion of returning "CREATE TABLE nnnn",
but for the moment backwards compatibility wins the day.
Andres Freund and Tom Lane
2012-03-20 02:37:19 +01:00
|
|
|
* plpgsql command, not just feed it to SPI_execute.) This is not
|
|
|
|
* a functional limitation because CREATE TABLE AS is allowed.
|
2001-02-09 01:14:26 +01:00
|
|
|
*/
|
Restructure SELECT INTO's parsetree representation into CreateTableAsStmt.
Making this operation look like a utility statement seems generally a good
idea, and particularly so in light of the desire to provide command
triggers for utility statements. The original choice of representing it as
SELECT with an IntoClause appendage had metastasized into rather a lot of
places, unfortunately, so that this patch is a great deal more complicated
than one might at first expect.
In particular, keeping EXPLAIN working for SELECT INTO and CREATE TABLE AS
subcommands required restructuring some EXPLAIN-related APIs. Add-on code
that calls ExplainOnePlan or ExplainOneUtility, or uses
ExplainOneQuery_hook, will need adjustment.
Also, the cases PREPARE ... SELECT INTO and CREATE RULE ... SELECT INTO,
which formerly were accepted though undocumented, are no longer accepted.
The PREPARE case can be replaced with use of CREATE TABLE AS EXECUTE.
The CREATE RULE case doesn't seem to have much real-world use (since the
rule would work only once before failing with "table already exists"),
so we'll not bother with that one.
Both SELECT INTO and CREATE TABLE AS still return a command tag of
"SELECT nnnn". There was some discussion of returning "CREATE TABLE nnnn",
but for the moment backwards compatibility wins the day.
Andres Freund and Tom Lane
2012-03-20 02:37:19 +01:00
|
|
|
ereport(ERROR,
|
2012-06-10 21:20:04 +02:00
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("EXECUTE of SELECT ... INTO is not implemented"),
|
|
|
|
errhint("You might want to use EXECUTE ... INTO or EXECUTE CREATE TABLE ... AS instead.")));
|
Restructure SELECT INTO's parsetree representation into CreateTableAsStmt.
Making this operation look like a utility statement seems generally a good
idea, and particularly so in light of the desire to provide command
triggers for utility statements. The original choice of representing it as
SELECT with an IntoClause appendage had metastasized into rather a lot of
places, unfortunately, so that this patch is a great deal more complicated
than one might at first expect.
In particular, keeping EXPLAIN working for SELECT INTO and CREATE TABLE AS
subcommands required restructuring some EXPLAIN-related APIs. Add-on code
that calls ExplainOnePlan or ExplainOneUtility, or uses
ExplainOneQuery_hook, will need adjustment.
Also, the cases PREPARE ... SELECT INTO and CREATE RULE ... SELECT INTO,
which formerly were accepted though undocumented, are no longer accepted.
The PREPARE case can be replaced with use of CREATE TABLE AS EXECUTE.
The CREATE RULE case doesn't seem to have much real-world use (since the
rule would work only once before failing with "table already exists"),
so we'll not bother with that one.
Both SELECT INTO and CREATE TABLE AS still return a command tag of
"SELECT nnnn". There was some discussion of returning "CREATE TABLE nnnn",
but for the moment backwards compatibility wins the day.
Andres Freund and Tom Lane
2012-03-20 02:37:19 +01:00
|
|
|
break;
|
2001-02-09 01:14:26 +01:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/* Some SPI errors deserve specific error messages */
|
2004-08-13 20:47:56 +02:00
|
|
|
case SPI_ERROR_COPY:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot COPY to/from client in PL/pgSQL")));
|
|
|
|
case SPI_ERROR_TRANSACTION:
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("cannot begin/end transactions in PL/pgSQL"),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errhint("Use a BEGIN block with an EXCEPTION clause instead.")));
|
2004-08-13 20:47:56 +02:00
|
|
|
|
2000-08-31 15:26:16 +02:00
|
|
|
default:
|
2004-09-13 22:10:13 +02:00
|
|
|
elog(ERROR, "SPI_execute failed executing query \"%s\": %s",
|
2004-07-31 22:55:45 +02:00
|
|
|
querystr, SPI_result_code_string(exec_res));
|
2000-08-31 15:26:16 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
/* Save result info for GET DIAGNOSTICS */
|
|
|
|
estate->eval_processed = SPI_processed;
|
|
|
|
estate->eval_lastoid = SPI_lastoid;
|
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
/* Process INTO if present */
|
|
|
|
if (stmt->into)
|
|
|
|
{
|
|
|
|
SPITupleTable *tuptab = SPI_tuptable;
|
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 n = SPI_processed;
|
2006-08-14 23:14:42 +02:00
|
|
|
PLpgSQL_rec *rec = NULL;
|
|
|
|
PLpgSQL_row *row = NULL;
|
|
|
|
|
|
|
|
/* If the statement did not return a tuple table, complain */
|
|
|
|
if (tuptab == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("INTO used with a command that cannot return data")));
|
2006-08-14 23:14:42 +02:00
|
|
|
|
|
|
|
/* Determine if we assign to a record or a row */
|
|
|
|
if (stmt->rec != NULL)
|
2008-11-05 01:07:54 +01:00
|
|
|
rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->dno]);
|
2006-08-14 23:14:42 +02:00
|
|
|
else if (stmt->row != NULL)
|
2008-11-05 01:07:54 +01:00
|
|
|
row = (PLpgSQL_row *) (estate->datums[stmt->row->dno]);
|
2006-08-14 23:14:42 +02:00
|
|
|
else
|
|
|
|
elog(ERROR, "unsupported target");
|
|
|
|
|
|
|
|
/*
|
2006-10-04 02:30:14 +02:00
|
|
|
* If SELECT ... INTO specified STRICT, and the query didn't find
|
|
|
|
* exactly one row, throw an error. If STRICT was not specified, then
|
|
|
|
* allow the query to find any number of rows.
|
2006-08-14 23:14:42 +02:00
|
|
|
*/
|
|
|
|
if (n == 0)
|
|
|
|
{
|
|
|
|
if (stmt->strict)
|
2013-10-07 21:38:49 +02:00
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
char *errdetail;
|
2013-10-07 21:38:49 +02:00
|
|
|
|
|
|
|
if (estate->func->print_strict_params)
|
|
|
|
errdetail = format_preparedparamsdata(estate, ppd);
|
|
|
|
else
|
|
|
|
errdetail = NULL;
|
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NO_DATA_FOUND),
|
2013-10-07 21:38:49 +02:00
|
|
|
errmsg("query returned no rows"),
|
2013-11-10 15:20:52 +01:00
|
|
|
errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
|
2013-10-07 21:38:49 +02:00
|
|
|
}
|
2006-08-14 23:14:42 +02:00
|
|
|
/* set the target to NULL(s) */
|
|
|
|
exec_move_row(estate, rec, row, NULL, tuptab->tupdesc);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (n > 1 && stmt->strict)
|
2013-10-07 21:38:49 +02:00
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
char *errdetail;
|
2013-10-07 21:38:49 +02:00
|
|
|
|
|
|
|
if (estate->func->print_strict_params)
|
|
|
|
errdetail = format_preparedparamsdata(estate, ppd);
|
|
|
|
else
|
|
|
|
errdetail = NULL;
|
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_TOO_MANY_ROWS),
|
2013-10-07 21:38:49 +02:00
|
|
|
errmsg("query returned more than one row"),
|
2013-11-10 15:20:52 +01:00
|
|
|
errdetail ? errdetail_internal("parameters: %s", errdetail) : 0));
|
2013-10-07 21:38:49 +02:00
|
|
|
}
|
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
/* Put the first result row into the target */
|
|
|
|
exec_move_row(estate, rec, row, tuptab->vals[0], tuptab->tupdesc);
|
|
|
|
}
|
2012-02-12 00:06:24 +01:00
|
|
|
/* clean up after exec_move_row() */
|
|
|
|
exec_eval_cleanup(estate);
|
2006-08-14 23:14:42 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* It might be a good idea to raise an error if the query returned
|
|
|
|
* tuples that are being ignored, but historically we have not done
|
|
|
|
* that.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Release any result from SPI_execute, as well as transient data */
|
2006-08-14 23:14:42 +02:00
|
|
|
SPI_freetuptable(SPI_tuptable);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextReset(stmt_mcontext);
|
2006-08-14 23:14:42 +02:00
|
|
|
|
2000-08-31 15:26:16 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_dynfors Execute a dynamic query, assign each
|
|
|
|
* tuple to a record or row and
|
|
|
|
* execute a group of statements
|
|
|
|
* for it.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
|
2000-08-31 15:26:16 +02:00
|
|
|
{
|
2001-05-21 16:22:19 +02:00
|
|
|
Portal portal;
|
2008-04-07 01:43:29 +02:00
|
|
|
int rc;
|
2000-08-31 15:26:16 +02:00
|
|
|
|
2010-01-19 02:35:31 +01:00
|
|
|
portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
|
|
|
|
NULL, 0);
|
2000-08-31 15:26:16 +02:00
|
|
|
|
2001-05-21 16:22:19 +02:00
|
|
|
/*
|
2008-04-07 01:43:29 +02:00
|
|
|
* Execute the loop
|
2003-03-02 21:45:47 +01:00
|
|
|
*/
|
2008-04-07 01:43:29 +02:00
|
|
|
rc = exec_for_query(estate, (PLpgSQL_stmt_forq *) stmt, portal, true);
|
2003-03-02 21:45:47 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Close the implicit cursor
|
2001-05-21 16:22:19 +02:00
|
|
|
*/
|
|
|
|
SPI_cursor_close(portal);
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
return rc;
|
2001-05-21 16:22:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_open Execute an OPEN cursor statement
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_open(PLpgSQL_execstate *estate, PLpgSQL_stmt_open *stmt)
|
2001-05-21 16:22:19 +02:00
|
|
|
{
|
2008-04-07 01:43:29 +02:00
|
|
|
PLpgSQL_var *curvar;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext stmt_mcontext = NULL;
|
2001-10-25 07:50:21 +02:00
|
|
|
char *curname = NULL;
|
2008-04-07 01:43:29 +02:00
|
|
|
PLpgSQL_expr *query;
|
2001-05-21 16:22:19 +02:00
|
|
|
Portal portal;
|
2009-11-04 23:26:08 +01:00
|
|
|
ParamListInfo paramLI;
|
2001-05-21 16:22:19 +02:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Get the cursor variable and if it has an assigned name, check
|
|
|
|
* that it's not in use currently.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
|
|
|
|
if (!curvar->isnull)
|
|
|
|
{
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
/* We only need stmt_mcontext to hold the cursor name string */
|
|
|
|
stmt_mcontext = get_stmt_mcontext(estate);
|
|
|
|
oldcontext = MemoryContextSwitchTo(stmt_mcontext);
|
2008-03-25 23:42:46 +01:00
|
|
|
curname = TextDatumGetCString(curvar->value);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2001-05-21 16:22:19 +02:00
|
|
|
if (SPI_cursor_find(curname) != NULL)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DUPLICATE_CURSOR),
|
|
|
|
errmsg("cursor \"%s\" already in use", curname)));
|
2001-05-21 16:22:19 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Process the OPEN according to it's type.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (stmt->query != NULL)
|
|
|
|
{
|
|
|
|
/* ----------
|
|
|
|
* This is an OPEN refcursor FOR SELECT ...
|
|
|
|
*
|
|
|
|
* We just make sure the query is planned. The real work is
|
|
|
|
* done downstairs.
|
|
|
|
* ----------
|
2000-08-31 15:26:16 +02:00
|
|
|
*/
|
2001-10-25 07:50:21 +02:00
|
|
|
query = stmt->query;
|
2001-05-21 16:22:19 +02:00
|
|
|
if (query->plan == NULL)
|
2007-04-16 19:21:24 +02:00
|
|
|
exec_prepare_plan(estate, query, stmt->cursor_options);
|
2001-05-21 16:22:19 +02:00
|
|
|
}
|
|
|
|
else if (stmt->dynquery != NULL)
|
|
|
|
{
|
|
|
|
/* ----------
|
|
|
|
* This is an OPEN refcursor FOR EXECUTE ...
|
|
|
|
* ----------
|
|
|
|
*/
|
2010-01-19 02:35:31 +01:00
|
|
|
portal = exec_dynquery_with_params(estate,
|
|
|
|
stmt->dynquery,
|
|
|
|
stmt->params,
|
|
|
|
curname,
|
|
|
|
stmt->cursor_options);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* If cursor variable was NULL, store the generated portal name in it.
|
|
|
|
* Note: exec_dynquery_with_params already reset the stmt_mcontext, so
|
|
|
|
* curname is a dangling pointer here; but testing it for nullness is
|
|
|
|
* OK.
|
2001-05-21 16:22:19 +02:00
|
|
|
*/
|
2008-04-07 01:43:29 +02:00
|
|
|
if (curname == NULL)
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(estate, curvar, portal->name);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* ----------
|
|
|
|
* This is an OPEN cursor
|
2001-11-16 00:31:09 +01:00
|
|
|
*
|
|
|
|
* Note: parser should already have checked that statement supplies
|
|
|
|
* args iff cursor needs them, but we check again to be safe.
|
2001-05-21 16:22:19 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (stmt->argquery != NULL)
|
2000-08-31 15:26:16 +02:00
|
|
|
{
|
2001-05-21 16:22:19 +02:00
|
|
|
/* ----------
|
2006-08-14 23:14:42 +02:00
|
|
|
* OPEN CURSOR with args. We fake a SELECT ... INTO ...
|
2001-05-21 16:22:19 +02:00
|
|
|
* statement to evaluate the args and put 'em into the
|
|
|
|
* internal row.
|
|
|
|
* ----------
|
|
|
|
*/
|
2006-08-14 23:14:42 +02:00
|
|
|
PLpgSQL_stmt_execsql set_args;
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2001-11-16 00:31:09 +01:00
|
|
|
if (curvar->cursor_explicit_argrow < 0)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("arguments given for cursor without arguments")));
|
2001-11-16 00:31:09 +01:00
|
|
|
|
2001-05-21 16:22:19 +02:00
|
|
|
memset(&set_args, 0, sizeof(set_args));
|
2006-08-14 23:14:42 +02:00
|
|
|
set_args.cmd_type = PLPGSQL_STMT_EXECSQL;
|
2001-10-25 07:50:21 +02:00
|
|
|
set_args.lineno = stmt->lineno;
|
2006-08-14 23:14:42 +02:00
|
|
|
set_args.sqlstmt = stmt->argquery;
|
|
|
|
set_args.into = true;
|
|
|
|
/* XXX historically this has not been STRICT */
|
2001-10-25 07:50:21 +02:00
|
|
|
set_args.row = (PLpgSQL_row *)
|
|
|
|
(estate->datums[curvar->cursor_explicit_argrow]);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2006-08-14 23:14:42 +02:00
|
|
|
if (exec_stmt_execsql(estate, &set_args) != PLPGSQL_RC_OK)
|
2001-05-21 16:22:19 +02:00
|
|
|
elog(ERROR, "open cursor failed during argument processing");
|
|
|
|
}
|
2001-11-16 00:31:09 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
if (curvar->cursor_explicit_argrow >= 0)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("arguments required for cursor")));
|
2001-11-16 00:31:09 +01:00
|
|
|
}
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2001-10-25 07:50:21 +02:00
|
|
|
query = curvar->cursor_explicit_expr;
|
2001-05-21 16:22:19 +02:00
|
|
|
if (query->plan == NULL)
|
2007-04-16 19:21:24 +02:00
|
|
|
exec_prepare_plan(estate, query, curvar->cursor_options);
|
2001-05-21 16:22:19 +02:00
|
|
|
}
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* Set up short-lived ParamListInfo
|
2001-05-21 16:22:19 +02:00
|
|
|
*/
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
paramLI = setup_unshared_param_list(estate, query);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
2001-05-21 16:22:19 +02:00
|
|
|
* Open the cursor
|
|
|
|
*/
|
2009-11-04 23:26:08 +01:00
|
|
|
portal = SPI_cursor_open_with_paramlist(curname, query->plan,
|
|
|
|
paramLI,
|
|
|
|
estate->readonly_func);
|
2001-05-21 16:22:19 +02:00
|
|
|
if (portal == NULL)
|
2004-07-31 22:55:45 +02:00
|
|
|
elog(ERROR, "could not open cursor: %s",
|
|
|
|
SPI_result_code_string(SPI_result));
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
|
|
|
* If cursor variable was NULL, store the generated portal name in it
|
|
|
|
*/
|
|
|
|
if (curname == NULL)
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(estate, curvar, portal->name);
|
2008-04-07 01:43:29 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* If we had any transient data, clean it up */
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
if (stmt_mcontext)
|
|
|
|
MemoryContextReset(stmt_mcontext);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
2007-04-29 03:21:09 +02:00
|
|
|
* exec_stmt_fetch Fetch from a cursor into a target, or just
|
2007-11-15 22:14:46 +01:00
|
|
|
* move the current position of the cursor
|
2001-05-21 16:22:19 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_fetch(PLpgSQL_execstate *estate, PLpgSQL_stmt_fetch *stmt)
|
2001-05-21 16:22:19 +02:00
|
|
|
{
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
PLpgSQL_var *curvar;
|
2001-05-21 16:22:19 +02:00
|
|
|
PLpgSQL_rec *rec = NULL;
|
|
|
|
PLpgSQL_row *row = NULL;
|
2007-04-16 19:21:24 +02:00
|
|
|
long how_many = stmt->how_many;
|
2001-08-02 23:31:23 +02:00
|
|
|
SPITupleTable *tuptab;
|
2001-05-21 16:22:19 +02:00
|
|
|
Portal portal;
|
2001-10-25 07:50:21 +02:00
|
|
|
char *curname;
|
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 n;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
2001-05-21 16:22:19 +02:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Get the portal of the cursor by name
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
|
|
|
|
if (curvar->isnull)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("cursor variable \"%s\" is null", curvar->refname)));
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
|
|
|
|
/* Use eval_mcontext for short-lived string */
|
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2008-03-25 23:42:46 +01:00
|
|
|
curname = TextDatumGetCString(curvar->value);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
|
|
|
portal = SPI_cursor_find(curname);
|
|
|
|
if (portal == NULL)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_CURSOR),
|
|
|
|
errmsg("cursor \"%s\" does not exist", curname)));
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2007-04-16 19:21:24 +02:00
|
|
|
/* Calculate position for FETCH_RELATIVE or FETCH_ABSOLUTE */
|
|
|
|
if (stmt->expr)
|
|
|
|
{
|
2007-11-15 22:14:46 +01:00
|
|
|
bool isnull;
|
2007-04-16 19:21:24 +02:00
|
|
|
|
|
|
|
/* XXX should be doing this in LONG not INT width */
|
|
|
|
how_many = exec_eval_integer(estate, stmt->expr, &isnull);
|
|
|
|
|
|
|
|
if (isnull)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("relative or absolute cursor position is null")));
|
2007-04-16 19:21:24 +02:00
|
|
|
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
}
|
|
|
|
|
2007-04-29 03:21:09 +02:00
|
|
|
if (!stmt->is_move)
|
|
|
|
{
|
|
|
|
/* ----------
|
|
|
|
* Determine if we fetch into a record or a row
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (stmt->rec != NULL)
|
2008-11-05 01:07:54 +01:00
|
|
|
rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->dno]);
|
2007-04-29 03:21:09 +02:00
|
|
|
else if (stmt->row != NULL)
|
2008-11-05 01:07:54 +01:00
|
|
|
row = (PLpgSQL_row *) (estate->datums[stmt->row->dno]);
|
2007-04-29 03:21:09 +02:00
|
|
|
else
|
|
|
|
elog(ERROR, "unsupported target");
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2007-04-29 03:21:09 +02:00
|
|
|
/* ----------
|
|
|
|
* Fetch 1 tuple from the cursor
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
SPI_scroll_cursor_fetch(portal, stmt->direction, how_many);
|
|
|
|
tuptab = SPI_tuptable;
|
|
|
|
n = SPI_processed;
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2007-04-29 03:21:09 +02:00
|
|
|
/* ----------
|
2009-04-02 22:16:30 +02:00
|
|
|
* Set the target appropriately.
|
2007-04-29 03:21:09 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
if (n == 0)
|
|
|
|
exec_move_row(estate, rec, row, NULL, tuptab->tupdesc);
|
|
|
|
else
|
|
|
|
exec_move_row(estate, rec, row, tuptab->vals[0], tuptab->tupdesc);
|
|
|
|
|
2012-02-12 00:06:24 +01:00
|
|
|
exec_eval_cleanup(estate);
|
2007-04-29 03:21:09 +02:00
|
|
|
SPI_freetuptable(tuptab);
|
2003-03-02 21:45:47 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-04-29 03:21:09 +02:00
|
|
|
/* Move the cursor */
|
|
|
|
SPI_scroll_cursor_move(portal, stmt->direction, how_many);
|
|
|
|
n = SPI_processed;
|
|
|
|
}
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2009-04-02 22:16:30 +02:00
|
|
|
/* Set the ROW_COUNT and the global FOUND variable appropriately. */
|
2009-04-02 21:20:45 +02:00
|
|
|
estate->eval_processed = n;
|
2009-04-02 22:16:30 +02:00
|
|
|
exec_set_found(estate, n != 0);
|
2009-04-02 21:20:45 +02:00
|
|
|
|
2001-05-21 16:22:19 +02:00
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_stmt_close Close a cursor
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_stmt_close(PLpgSQL_execstate *estate, PLpgSQL_stmt_close *stmt)
|
2001-05-21 16:22:19 +02:00
|
|
|
{
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
PLpgSQL_var *curvar;
|
2001-05-21 16:22:19 +02:00
|
|
|
Portal portal;
|
2001-10-25 07:50:21 +02:00
|
|
|
char *curname;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
2001-05-21 16:22:19 +02:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* Get the portal of the cursor by name
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
curvar = (PLpgSQL_var *) (estate->datums[stmt->curvar]);
|
|
|
|
if (curvar->isnull)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("cursor variable \"%s\" is null", curvar->refname)));
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
|
|
|
|
/* Use eval_mcontext for short-lived string */
|
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2008-03-25 23:42:46 +01:00
|
|
|
curname = TextDatumGetCString(curvar->value);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
|
|
|
portal = SPI_cursor_find(curname);
|
|
|
|
if (portal == NULL)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_CURSOR),
|
|
|
|
errmsg("cursor \"%s\" does not exist", curname)));
|
2001-05-21 16:22:19 +02:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* And close it.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
SPI_cursor_close(portal);
|
2000-08-31 15:26:16 +02:00
|
|
|
|
|
|
|
return PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
2011-07-18 20:46:27 +02:00
|
|
|
* exec_assign_expr Put an expression's result into a variable.
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_assign_expr(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
|
|
|
|
PLpgSQL_expr *expr)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
Datum value;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
bool isnull;
|
1998-09-01 06:40:42 +02:00
|
|
|
Oid valtype;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 valtypmod;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
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
|
|
|
/*
|
|
|
|
* If first time through, create a plan for this expression, and then see
|
|
|
|
* if we can pass the target variable as a read-write parameter to the
|
|
|
|
* expression. (This is a bit messy, but it seems cleaner than modifying
|
|
|
|
* the API of exec_eval_expr for the purpose.)
|
|
|
|
*/
|
|
|
|
if (expr->plan == NULL)
|
|
|
|
{
|
|
|
|
exec_prepare_plan(estate, expr, 0);
|
|
|
|
if (target->dtype == PLPGSQL_DTYPE_VAR)
|
|
|
|
exec_check_rw_parameter(expr, target->dno);
|
|
|
|
}
|
|
|
|
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
value = exec_eval_expr(estate, expr, &isnull, &valtype, &valtypmod);
|
|
|
|
exec_assign_value(estate, target, value, isnull, valtype, valtypmod);
|
2001-08-02 23:31:23 +02:00
|
|
|
exec_eval_cleanup(estate);
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2011-07-18 20:46:27 +02:00
|
|
|
/* ----------
|
|
|
|
* exec_assign_c_string Put a C string into a text variable.
|
|
|
|
*
|
|
|
|
* We take a NULL pointer as signifying empty string, not SQL null.
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
*
|
|
|
|
* As with the underlying exec_assign_value, caller is expected to do
|
|
|
|
* exec_eval_cleanup later.
|
2011-07-18 20:46:27 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
exec_assign_c_string(PLpgSQL_execstate *estate, PLpgSQL_datum *target,
|
|
|
|
const char *str)
|
|
|
|
{
|
|
|
|
text *value;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
2011-07-18 20:46:27 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* Use eval_mcontext for short-lived text value */
|
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2011-07-18 20:46:27 +02:00
|
|
|
if (str != NULL)
|
|
|
|
value = cstring_to_text(str);
|
|
|
|
else
|
|
|
|
value = cstring_to_text("");
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
exec_assign_value(estate, target, PointerGetDatum(value), false,
|
|
|
|
TEXTOID, -1);
|
2011-07-18 20:46:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
* exec_assign_value Put a value into a target datum
|
2010-08-09 20:50:11 +02:00
|
|
|
*
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* Note: in some code paths, this will leak memory in the eval_mcontext;
|
2010-08-09 20:50:11 +02:00
|
|
|
* we assume that will be cleaned up later by exec_eval_cleanup. We cannot
|
|
|
|
* call exec_eval_cleanup here for fear of destroying the input Datum value.
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_assign_value(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_datum *target,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Datum value, bool isNull,
|
|
|
|
Oid valtype, int32 valtypmod)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
switch (target->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_VAR:
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Target is a variable
|
|
|
|
*/
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) target;
|
|
|
|
Datum newvalue;
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2012-02-12 00:06:24 +01:00
|
|
|
newvalue = exec_cast_value(estate,
|
|
|
|
value,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
&isNull,
|
2012-02-12 00:06:24 +01:00
|
|
|
valtype,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
valtypmod,
|
2012-02-12 00:06:24 +01:00
|
|
|
var->datatype->typoid,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
var->datatype->atttypmod);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
if (isNull && var->notnull)
|
2004-08-29 07:07:03 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("null value cannot be assigned to variable \"%s\" declared NOT NULL",
|
2004-08-29 07:07:03 +02:00
|
|
|
var->refname)));
|
2001-08-02 23:31:23 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
2012-02-12 00:06:24 +01:00
|
|
|
* If type is by-reference, copy the new value (which is
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* probably in the eval_mcontext) into the procedure's main
|
|
|
|
* memory context. But if it's a read/write reference to an
|
|
|
|
* expanded object, no physical copy needs to happen; at most
|
|
|
|
* we need to reparent the object's memory context.
|
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
|
|
|
*
|
|
|
|
* If it's an array, we force the value to be stored in R/W
|
|
|
|
* expanded form. This wins if the function later does, say,
|
|
|
|
* a lot of array subscripting operations on the variable, and
|
|
|
|
* otherwise might lose. We might need to use a different
|
|
|
|
* heuristic, but it's too soon to tell. Also, are there
|
|
|
|
* cases where it'd be useful to force non-array values into
|
|
|
|
* expanded form?
|
2004-08-29 07:07:03 +02:00
|
|
|
*/
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
if (!var->datatype->typbyval && !isNull)
|
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
|
|
|
{
|
|
|
|
if (var->datatype->typisarray &&
|
|
|
|
!VARATT_IS_EXTERNAL_EXPANDED_RW(DatumGetPointer(newvalue)))
|
|
|
|
{
|
|
|
|
/* array and not already R/W, so apply expand_array */
|
|
|
|
newvalue = expand_array(newvalue,
|
|
|
|
CurrentMemoryContext,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* else transfer value if R/W, else just datumCopy */
|
|
|
|
newvalue = datumTransfer(newvalue,
|
|
|
|
false,
|
|
|
|
var->datatype->typlen);
|
|
|
|
}
|
|
|
|
}
|
2005-06-20 22:44:44 +02:00
|
|
|
|
|
|
|
/*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* Now free the old value, if any, and assign the new one. But
|
|
|
|
* skip the assignment if old and new values are the same.
|
|
|
|
* Note that for expanded objects, this test is necessary and
|
|
|
|
* cannot reliably be made any earlier; we have to be looking
|
|
|
|
* at the object's standard R/W pointer to be sure pointer
|
|
|
|
* equality is meaningful.
|
2005-06-20 22:44:44 +02:00
|
|
|
*/
|
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
|
|
|
if (var->value != newvalue || var->isnull || isNull)
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(estate, var, newvalue, isNull,
|
|
|
|
(!var->datatype->typbyval && !isNull));
|
2004-08-29 07:07:03 +02:00
|
|
|
break;
|
2001-05-21 16:22:19 +02:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2004-06-04 04:37:06 +02:00
|
|
|
case PLPGSQL_DTYPE_ROW:
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
|
|
|
* Target is a row variable
|
|
|
|
*/
|
|
|
|
PLpgSQL_row *row = (PLpgSQL_row *) target;
|
|
|
|
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
if (isNull)
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
|
|
|
/* If source is null, just assign nulls to the row */
|
|
|
|
exec_move_row(estate, NULL, row, NULL, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-02-12 20:37:36 +01:00
|
|
|
/* Source must be of RECORD or composite type */
|
|
|
|
if (!type_is_rowtype(valtype))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("cannot assign non-composite value to a row variable")));
|
2012-12-07 05:09:52 +01:00
|
|
|
exec_move_row_from_datum(estate, NULL, row, value);
|
2004-08-29 07:07:03 +02:00
|
|
|
}
|
|
|
|
break;
|
2004-06-04 04:37:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_REC:
|
|
|
|
{
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
|
|
|
* Target is a record variable
|
|
|
|
*/
|
|
|
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) target;
|
|
|
|
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
if (isNull)
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
|
|
|
/* If source is null, just assign nulls to the record */
|
|
|
|
exec_move_row(estate, rec, NULL, NULL, NULL);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-02-12 20:37:36 +01:00
|
|
|
/* Source must be of RECORD or composite type */
|
|
|
|
if (!type_is_rowtype(valtype))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("cannot assign non-composite value to a record variable")));
|
2012-12-07 05:09:52 +01:00
|
|
|
exec_move_row_from_datum(estate, rec, NULL, value);
|
2004-08-29 07:07:03 +02:00
|
|
|
}
|
|
|
|
break;
|
2004-06-04 04:37:06 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_RECFIELD:
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Target is a field of a record
|
|
|
|
*/
|
|
|
|
PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) target;
|
|
|
|
PLpgSQL_rec *rec;
|
2006-05-30 15:40:56 +02:00
|
|
|
int fno;
|
2004-08-29 07:07:03 +02:00
|
|
|
HeapTuple newtup;
|
2016-11-08 21:36:36 +01:00
|
|
|
int colnums[1];
|
|
|
|
Datum values[1];
|
|
|
|
bool nulls[1];
|
2004-08-29 07:07:03 +02:00
|
|
|
Oid atttype;
|
|
|
|
int32 atttypmod;
|
|
|
|
|
|
|
|
rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Check that there is already a tuple in the record. We need
|
|
|
|
* that because records don't have any predefined field
|
|
|
|
* structure.
|
2004-08-29 07:07:03 +02:00
|
|
|
*/
|
|
|
|
if (!HeapTupleIsValid(rec->tup))
|
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("record \"%s\" is not assigned yet",
|
|
|
|
rec->refname),
|
|
|
|
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
2016-11-08 21:36:36 +01:00
|
|
|
* Get the number of the record field to change. Disallow
|
|
|
|
* system columns because the code below won't cope.
|
2004-08-29 07:07:03 +02:00
|
|
|
*/
|
2006-05-30 15:40:56 +02:00
|
|
|
fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
|
2008-11-02 02:45:28 +01:00
|
|
|
if (fno <= 0)
|
2004-08-29 07:07:03 +02:00
|
|
|
ereport(ERROR,
|
2006-05-30 15:40:56 +02:00
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("record \"%s\" has no field \"%s\"",
|
|
|
|
rec->refname, recfield->fieldname)));
|
2016-11-08 21:36:36 +01:00
|
|
|
colnums[0] = fno;
|
2004-08-29 07:07:03 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Now insert the new value, being careful to cast it to the
|
|
|
|
* right type.
|
2004-08-29 07:07:03 +02:00
|
|
|
*/
|
2017-08-20 20:19:07 +02:00
|
|
|
atttype = TupleDescAttr(rec->tupdesc, fno - 1)->atttypid;
|
|
|
|
atttypmod = TupleDescAttr(rec->tupdesc, fno - 1)->atttypmod;
|
2016-11-08 21:36:36 +01:00
|
|
|
values[0] = exec_cast_value(estate,
|
|
|
|
value,
|
|
|
|
&isNull,
|
|
|
|
valtype,
|
|
|
|
valtypmod,
|
|
|
|
atttype,
|
|
|
|
atttypmod);
|
|
|
|
nulls[0] = isNull;
|
|
|
|
|
|
|
|
newtup = heap_modify_tuple_by_cols(rec->tup, rec->tupdesc,
|
|
|
|
1, colnums, values, nulls);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
if (rec->freetup)
|
|
|
|
heap_freetuple(rec->tup);
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
rec->tup = newtup;
|
|
|
|
rec->freetup = true;
|
2001-05-21 16:22:19 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
break;
|
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2003-03-25 04:16:41 +01:00
|
|
|
case PLPGSQL_DTYPE_ARRAYELEM:
|
2003-08-04 02:43:34 +02:00
|
|
|
{
|
2010-08-09 20:50:11 +02:00
|
|
|
/*
|
|
|
|
* Target is an element of an array
|
|
|
|
*/
|
2011-09-26 21:38:07 +02:00
|
|
|
PLpgSQL_arrayelem *arrayelem;
|
2004-08-29 07:07:03 +02:00
|
|
|
int nsubscripts;
|
|
|
|
int i;
|
|
|
|
PLpgSQL_expr *subscripts[MAXDIM];
|
|
|
|
int subscriptvals[MAXDIM];
|
2005-02-01 20:35:14 +01:00
|
|
|
Datum oldarraydatum,
|
Rationalize the APIs of array element/slice access functions.
The four functions array_ref, array_set, array_get_slice, array_set_slice
have traditionally declared their array inputs and results as being of type
"ArrayType *". This is a lie, and has been since Berkeley days, because
they actually also support "fixed-length array" types such as "name" and
"point"; not to mention that the inputs could be toasted. These values
should be declared Datum instead to avoid confusion. The current coding
already risks possible misoptimization by compilers, and it'll get worse
when "expanded" array representations become a valid alternative.
However, there's a fair amount of code using array_ref and array_set with
arrays that *are* known to be ArrayType structures, and there might be more
such places in third-party code. Rather than cluttering those call sites
with PointerGetDatum/DatumGetArrayTypeP cruft, what I did was to rename the
existing functions to array_get_element/array_set_element, fix their
signatures, then reincarnate array_ref/array_set as backwards compatibility
wrappers.
array_get_slice/array_set_slice have no such constituency in the core code,
and probably not in third-party code either, so I just changed their APIs.
2015-02-16 18:23:58 +01:00
|
|
|
newarraydatum,
|
2004-08-29 07:07:03 +02:00
|
|
|
coerced_value;
|
2011-09-26 21:38:07 +02:00
|
|
|
bool oldarrayisnull;
|
|
|
|
Oid parenttypoid;
|
|
|
|
int32 parenttypmod;
|
2010-08-09 20:50:11 +02:00
|
|
|
SPITupleTable *save_eval_tuptable;
|
2012-02-12 00:06:24 +01:00
|
|
|
MemoryContext oldcontext;
|
2010-08-09 20:50:11 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* We need to do subscript evaluation, which might require
|
|
|
|
* evaluating general expressions; and the caller might have
|
2011-04-10 17:42:00 +02:00
|
|
|
* done that too in order to prepare the input Datum. We have
|
|
|
|
* to save and restore the caller's SPI_execute result, if
|
|
|
|
* any.
|
2010-08-09 20:50:11 +02:00
|
|
|
*/
|
|
|
|
save_eval_tuptable = estate->eval_tuptable;
|
|
|
|
estate->eval_tuptable = NULL;
|
2003-03-25 04:16:41 +01:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
2005-11-22 19:17:34 +01:00
|
|
|
* To handle constructs like x[1][2] := something, we have to
|
|
|
|
* be prepared to deal with a chain of arrayelem datums. Chase
|
2005-10-15 04:49:52 +02:00
|
|
|
* back to find the base array datum, and save the subscript
|
|
|
|
* expressions as we go. (We are scanning right to left here,
|
|
|
|
* but want to evaluate the subscripts left-to-right to
|
2011-09-26 21:38:07 +02:00
|
|
|
* minimize surprises.) Note that arrayelem is left pointing
|
|
|
|
* to the leftmost arrayelem datum, where we will cache the
|
|
|
|
* array element type data.
|
2004-08-29 07:07:03 +02:00
|
|
|
*/
|
|
|
|
nsubscripts = 0;
|
|
|
|
do
|
|
|
|
{
|
2011-09-26 21:38:07 +02:00
|
|
|
arrayelem = (PLpgSQL_arrayelem *) target;
|
2004-08-29 07:07:03 +02:00
|
|
|
if (nsubscripts >= MAXDIM)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("number of array dimensions (%d) exceeds the maximum allowed (%d)",
|
2011-02-01 07:21:32 +01:00
|
|
|
nsubscripts + 1, MAXDIM)));
|
2004-08-29 07:07:03 +02:00
|
|
|
subscripts[nsubscripts++] = arrayelem->subscript;
|
|
|
|
target = estate->datums[arrayelem->arrayparentno];
|
|
|
|
} while (target->dtype == PLPGSQL_DTYPE_ARRAYELEM);
|
|
|
|
|
|
|
|
/* Fetch current value of array datum */
|
2009-11-04 23:26:08 +01:00
|
|
|
exec_eval_datum(estate, target,
|
2011-09-26 21:38:07 +02:00
|
|
|
&parenttypoid, &parenttypmod,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
&oldarraydatum, &oldarrayisnull);
|
2003-03-25 04:16:41 +01:00
|
|
|
|
2011-09-26 21:38:07 +02:00
|
|
|
/* Update cached type data if necessary */
|
|
|
|
if (arrayelem->parenttypoid != parenttypoid ||
|
|
|
|
arrayelem->parenttypmod != parenttypmod)
|
|
|
|
{
|
|
|
|
Oid arraytypoid;
|
|
|
|
int32 arraytypmod = parenttypmod;
|
|
|
|
int16 arraytyplen;
|
|
|
|
Oid elemtypoid;
|
|
|
|
int16 elemtyplen;
|
|
|
|
bool elemtypbyval;
|
|
|
|
char elemtypalign;
|
|
|
|
|
|
|
|
/* If target is domain over array, reduce to base type */
|
|
|
|
arraytypoid = getBaseTypeAndTypmod(parenttypoid,
|
|
|
|
&arraytypmod);
|
|
|
|
|
|
|
|
/* ... and identify the element type */
|
|
|
|
elemtypoid = get_element_type(arraytypoid);
|
|
|
|
if (!OidIsValid(elemtypoid))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
errmsg("subscripted object is not an array")));
|
2011-09-26 21:38:07 +02:00
|
|
|
|
|
|
|
/* Collect needed data about the types */
|
|
|
|
arraytyplen = get_typlen(arraytypoid);
|
|
|
|
|
|
|
|
get_typlenbyvalalign(elemtypoid,
|
|
|
|
&elemtyplen,
|
|
|
|
&elemtypbyval,
|
|
|
|
&elemtypalign);
|
|
|
|
|
|
|
|
/* Now safe to update the cached data */
|
|
|
|
arrayelem->parenttypoid = parenttypoid;
|
|
|
|
arrayelem->parenttypmod = parenttypmod;
|
|
|
|
arrayelem->arraytypoid = arraytypoid;
|
|
|
|
arrayelem->arraytypmod = arraytypmod;
|
|
|
|
arrayelem->arraytyplen = arraytyplen;
|
|
|
|
arrayelem->elemtypoid = elemtypoid;
|
|
|
|
arrayelem->elemtyplen = elemtyplen;
|
|
|
|
arrayelem->elemtypbyval = elemtypbyval;
|
|
|
|
arrayelem->elemtypalign = elemtypalign;
|
|
|
|
}
|
2005-02-01 20:35:14 +01:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
2005-11-18 03:38:24 +01:00
|
|
|
* Evaluate the subscripts, switch into left-to-right order.
|
Faster expression evaluation and targetlist projection.
This replaces the old, recursive tree-walk based evaluation, with
non-recursive, opcode dispatch based, expression evaluation.
Projection is now implemented as part of expression evaluation.
This both leads to significant performance improvements, and makes
future just-in-time compilation of expressions easier.
The speed gains primarily come from:
- non-recursive implementation reduces stack usage / overhead
- simple sub-expressions are implemented with a single jump, without
function calls
- sharing some state between different sub-expressions
- reduced amount of indirect/hard to predict memory accesses by laying
out operation metadata sequentially; including the avoidance of
nearly all of the previously used linked lists
- more code has been moved to expression initialization, avoiding
constant re-checks at evaluation time
Future just-in-time compilation (JIT) has become easier, as
demonstrated by released patches intended to be merged in a later
release, for primarily two reasons: Firstly, due to a stricter split
between expression initialization and evaluation, less code has to be
handled by the JIT. Secondly, due to the non-recursive nature of the
generated "instructions", less performance-critical code-paths can
easily be shared between interpreted and compiled evaluation.
The new framework allows for significant future optimizations. E.g.:
- basic infrastructure for to later reduce the per executor-startup
overhead of expression evaluation, by caching state in prepared
statements. That'd be helpful in OLTPish scenarios where
initialization overhead is measurable.
- optimizing the generated "code". A number of proposals for potential
work has already been made.
- optimizing the interpreter. Similarly a number of proposals have
been made here too.
The move of logic into the expression initialization step leads to some
backward-incompatible changes:
- Function permission checks are now done during expression
initialization, whereas previously they were done during
execution. In edge cases this can lead to errors being raised that
previously wouldn't have been, e.g. a NULL array being coerced to a
different array type previously didn't perform checks.
- The set of domain constraints to be checked, is now evaluated once
during expression initialization, previously it was re-built
every time a domain check was evaluated. For normal queries this
doesn't change much, but e.g. for plpgsql functions, which caches
ExprStates, the old set could stick around longer. The behavior
around might still change.
Author: Andres Freund, with significant changes by Tom Lane,
changes by Heikki Linnakangas
Reviewed-By: Tom Lane, Heikki Linnakangas
Discussion: https://postgr.es/m/20161206034955.bh33paeralxbtluv@alap3.anarazel.de
2017-03-14 23:45:36 +01:00
|
|
|
* Like the expression built by ExecInitArrayRef(), complain
|
|
|
|
* if any subscript is null.
|
2004-08-29 07:07:03 +02:00
|
|
|
*/
|
|
|
|
for (i = 0; i < nsubscripts; i++)
|
|
|
|
{
|
|
|
|
bool subisnull;
|
2003-03-25 04:16:41 +01:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
subscriptvals[i] =
|
|
|
|
exec_eval_integer(estate,
|
|
|
|
subscripts[nsubscripts - 1 - i],
|
|
|
|
&subisnull);
|
2005-11-18 03:38:24 +01:00
|
|
|
if (subisnull)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("array subscript in assignment must not be null")));
|
2010-08-09 20:50:11 +02:00
|
|
|
|
|
|
|
/*
|
2011-04-10 17:42:00 +02:00
|
|
|
* Clean up in case the subscript expression wasn't
|
|
|
|
* simple. We can't do exec_eval_cleanup, but we can do
|
|
|
|
* this much (which is safe because the integer subscript
|
|
|
|
* value is surely pass-by-value), and we must do it in
|
|
|
|
* case the next subscript expression isn't simple either.
|
2010-08-09 20:50:11 +02:00
|
|
|
*/
|
|
|
|
if (estate->eval_tuptable != NULL)
|
|
|
|
SPI_freetuptable(estate->eval_tuptable);
|
|
|
|
estate->eval_tuptable = NULL;
|
2004-08-29 07:07:03 +02:00
|
|
|
}
|
2003-03-25 04:16:41 +01:00
|
|
|
|
2010-08-09 20:50:11 +02:00
|
|
|
/* Now we can restore caller's SPI_execute result if any. */
|
|
|
|
Assert(estate->eval_tuptable == NULL);
|
|
|
|
estate->eval_tuptable = save_eval_tuptable;
|
|
|
|
|
2005-11-18 03:38:24 +01:00
|
|
|
/* Coerce source value to match array element type. */
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
coerced_value = exec_cast_value(estate,
|
|
|
|
value,
|
|
|
|
&isNull,
|
|
|
|
valtype,
|
|
|
|
valtypmod,
|
|
|
|
arrayelem->elemtypoid,
|
|
|
|
arrayelem->arraytypmod);
|
2003-03-25 04:16:41 +01:00
|
|
|
|
2005-02-01 20:35:14 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If the original array is null, cons up an empty array so
|
|
|
|
* that the assignment can proceed; we'll end with a
|
2005-02-01 20:35:14 +01:00
|
|
|
* one-element array containing just the assigned-to
|
2005-10-15 04:49:52 +02:00
|
|
|
* subscript. This only works for varlena arrays, though; for
|
2005-11-18 03:38:24 +01:00
|
|
|
* fixed-length array types we skip the assignment. We can't
|
|
|
|
* support assignment of a null entry into a fixed-length
|
2005-11-22 19:17:34 +01:00
|
|
|
* array, either, so that's a no-op too. This is all ugly but
|
2017-03-26 17:36:46 +02:00
|
|
|
* corresponds to the current behavior of execExpr*.c.
|
2005-02-01 20:35:14 +01:00
|
|
|
*/
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
if (arrayelem->arraytyplen > 0 && /* fixed-length array? */
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
(oldarrayisnull || isNull))
|
2005-11-18 03:38:24 +01:00
|
|
|
return;
|
2005-02-01 20:35:14 +01:00
|
|
|
|
Rationalize the APIs of array element/slice access functions.
The four functions array_ref, array_set, array_get_slice, array_set_slice
have traditionally declared their array inputs and results as being of type
"ArrayType *". This is a lie, and has been since Berkeley days, because
they actually also support "fixed-length array" types such as "name" and
"point"; not to mention that the inputs could be toasted. These values
should be declared Datum instead to avoid confusion. The current coding
already risks possible misoptimization by compilers, and it'll get worse
when "expanded" array representations become a valid alternative.
However, there's a fair amount of code using array_ref and array_set with
arrays that *are* known to be ArrayType structures, and there might be more
such places in third-party code. Rather than cluttering those call sites
with PointerGetDatum/DatumGetArrayTypeP cruft, what I did was to rename the
existing functions to array_get_element/array_set_element, fix their
signatures, then reincarnate array_ref/array_set as backwards compatibility
wrappers.
array_get_slice/array_set_slice have no such constituency in the core code,
and probably not in third-party code either, so I just changed their APIs.
2015-02-16 18:23:58 +01:00
|
|
|
/* empty array, if any, and newarraydatum are short-lived */
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2012-02-12 00:06:24 +01:00
|
|
|
|
2005-11-18 03:38:24 +01:00
|
|
|
if (oldarrayisnull)
|
Rationalize the APIs of array element/slice access functions.
The four functions array_ref, array_set, array_get_slice, array_set_slice
have traditionally declared their array inputs and results as being of type
"ArrayType *". This is a lie, and has been since Berkeley days, because
they actually also support "fixed-length array" types such as "name" and
"point"; not to mention that the inputs could be toasted. These values
should be declared Datum instead to avoid confusion. The current coding
already risks possible misoptimization by compilers, and it'll get worse
when "expanded" array representations become a valid alternative.
However, there's a fair amount of code using array_ref and array_set with
arrays that *are* known to be ArrayType structures, and there might be more
such places in third-party code. Rather than cluttering those call sites
with PointerGetDatum/DatumGetArrayTypeP cruft, what I did was to rename the
existing functions to array_get_element/array_set_element, fix their
signatures, then reincarnate array_ref/array_set as backwards compatibility
wrappers.
array_get_slice/array_set_slice have no such constituency in the core code,
and probably not in third-party code either, so I just changed their APIs.
2015-02-16 18:23:58 +01:00
|
|
|
oldarraydatum = PointerGetDatum(construct_empty_array(arrayelem->elemtypoid));
|
2005-02-01 20:35:14 +01:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
/*
|
|
|
|
* Build the modified array value.
|
|
|
|
*/
|
Rationalize the APIs of array element/slice access functions.
The four functions array_ref, array_set, array_get_slice, array_set_slice
have traditionally declared their array inputs and results as being of type
"ArrayType *". This is a lie, and has been since Berkeley days, because
they actually also support "fixed-length array" types such as "name" and
"point"; not to mention that the inputs could be toasted. These values
should be declared Datum instead to avoid confusion. The current coding
already risks possible misoptimization by compilers, and it'll get worse
when "expanded" array representations become a valid alternative.
However, there's a fair amount of code using array_ref and array_set with
arrays that *are* known to be ArrayType structures, and there might be more
such places in third-party code. Rather than cluttering those call sites
with PointerGetDatum/DatumGetArrayTypeP cruft, what I did was to rename the
existing functions to array_get_element/array_set_element, fix their
signatures, then reincarnate array_ref/array_set as backwards compatibility
wrappers.
array_get_slice/array_set_slice have no such constituency in the core code,
and probably not in third-party code either, so I just changed their APIs.
2015-02-16 18:23:58 +01:00
|
|
|
newarraydatum = array_set_element(oldarraydatum,
|
|
|
|
nsubscripts,
|
|
|
|
subscriptvals,
|
|
|
|
coerced_value,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
isNull,
|
Rationalize the APIs of array element/slice access functions.
The four functions array_ref, array_set, array_get_slice, array_set_slice
have traditionally declared their array inputs and results as being of type
"ArrayType *". This is a lie, and has been since Berkeley days, because
they actually also support "fixed-length array" types such as "name" and
"point"; not to mention that the inputs could be toasted. These values
should be declared Datum instead to avoid confusion. The current coding
already risks possible misoptimization by compilers, and it'll get worse
when "expanded" array representations become a valid alternative.
However, there's a fair amount of code using array_ref and array_set with
arrays that *are* known to be ArrayType structures, and there might be more
such places in third-party code. Rather than cluttering those call sites
with PointerGetDatum/DatumGetArrayTypeP cruft, what I did was to rename the
existing functions to array_get_element/array_set_element, fix their
signatures, then reincarnate array_ref/array_set as backwards compatibility
wrappers.
array_get_slice/array_set_slice have no such constituency in the core code,
and probably not in third-party code either, so I just changed their APIs.
2015-02-16 18:23:58 +01:00
|
|
|
arrayelem->arraytyplen,
|
|
|
|
arrayelem->elemtyplen,
|
|
|
|
arrayelem->elemtypbyval,
|
|
|
|
arrayelem->elemtypalign);
|
2003-03-25 04:16:41 +01:00
|
|
|
|
2012-02-12 00:06:24 +01:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2003-03-25 04:16:41 +01:00
|
|
|
|
2005-11-17 23:14:56 +01:00
|
|
|
/*
|
2005-11-22 19:17:34 +01:00
|
|
|
* Assign the new array to the base variable. It's never NULL
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
* at this point. Note that if the target is a domain,
|
|
|
|
* coercing the base array type back up to the domain will
|
|
|
|
* happen within exec_assign_value.
|
2005-11-17 23:14:56 +01:00
|
|
|
*/
|
|
|
|
exec_assign_value(estate, target,
|
Rationalize the APIs of array element/slice access functions.
The four functions array_ref, array_set, array_get_slice, array_set_slice
have traditionally declared their array inputs and results as being of type
"ArrayType *". This is a lie, and has been since Berkeley days, because
they actually also support "fixed-length array" types such as "name" and
"point"; not to mention that the inputs could be toasted. These values
should be declared Datum instead to avoid confusion. The current coding
already risks possible misoptimization by compilers, and it'll get worse
when "expanded" array representations become a valid alternative.
However, there's a fair amount of code using array_ref and array_set with
arrays that *are* known to be ArrayType structures, and there might be more
such places in third-party code. Rather than cluttering those call sites
with PointerGetDatum/DatumGetArrayTypeP cruft, what I did was to rename the
existing functions to array_get_element/array_set_element, fix their
signatures, then reincarnate array_ref/array_set as backwards compatibility
wrappers.
array_get_slice/array_set_slice have no such constituency in the core code,
and probably not in third-party code either, so I just changed their APIs.
2015-02-16 18:23:58 +01:00
|
|
|
newarraydatum,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
false,
|
|
|
|
arrayelem->arraytypoid,
|
|
|
|
arrayelem->arraytypmod);
|
2004-08-29 07:07:03 +02:00
|
|
|
break;
|
|
|
|
}
|
2003-03-25 04:16:41 +01:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
default:
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized dtype: %d", target->dtype);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2003-03-25 01:34:24 +01:00
|
|
|
/*
|
|
|
|
* exec_eval_datum Get current value of a PLpgSQL_datum
|
|
|
|
*
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
* The type oid, typmod, value in Datum format, and null flag are returned.
|
2003-03-25 01:34:24 +01:00
|
|
|
*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* At present this doesn't handle PLpgSQL_expr or PLpgSQL_arrayelem datums;
|
|
|
|
* that's not needed because we never pass references to such datums to SPI.
|
2003-03-25 01:34:24 +01:00
|
|
|
*
|
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
|
|
|
* NOTE: the returned Datum points right at the stored value in the case of
|
|
|
|
* pass-by-reference datatypes. Generally callers should take care not to
|
|
|
|
* modify the stored value. Some callers intentionally manipulate variables
|
|
|
|
* referenced by R/W expanded pointers, though; it is those callers'
|
|
|
|
* responsibility that the results are semantically OK.
|
|
|
|
*
|
|
|
|
* In some cases we have to palloc a return value, and in such cases we put
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* it into the estate's eval_mcontext.
|
2003-03-25 01:34:24 +01:00
|
|
|
*/
|
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_eval_datum(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_datum *datum,
|
2003-03-25 01:34:24 +01:00
|
|
|
Oid *typeid,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
int32 *typetypmod,
|
2003-03-25 01:34:24 +01:00
|
|
|
Datum *value,
|
|
|
|
bool *isnull)
|
|
|
|
{
|
2005-06-21 00:51:29 +02:00
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
2003-03-25 01:34:24 +01:00
|
|
|
switch (datum->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_VAR:
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) datum;
|
2004-06-04 02:07:52 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
*typeid = var->datatype->typoid;
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
*typetypmod = var->datatype->atttypmod;
|
2004-08-29 07:07:03 +02:00
|
|
|
*value = var->value;
|
|
|
|
*isnull = var->isnull;
|
|
|
|
break;
|
|
|
|
}
|
2004-06-04 02:07:52 +02:00
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_ROW:
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_row *row = (PLpgSQL_row *) datum;
|
|
|
|
HeapTuple tup;
|
|
|
|
|
|
|
|
if (!row->rowtupdesc) /* should not happen */
|
|
|
|
elog(ERROR, "row variable has no tupdesc");
|
|
|
|
/* Make sure we have a valid type/typmod setting */
|
|
|
|
BlessTupleDesc(row->rowtupdesc);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2004-08-29 07:07:03 +02:00
|
|
|
tup = make_tuple_from_row(estate, row, row->rowtupdesc);
|
|
|
|
if (tup == NULL) /* should not happen */
|
|
|
|
elog(ERROR, "row not compatible with its own tupdesc");
|
|
|
|
*typeid = row->rowtupdesc->tdtypeid;
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
*typetypmod = row->rowtupdesc->tdtypmod;
|
2004-08-29 07:07:03 +02:00
|
|
|
*value = HeapTupleGetDatum(tup);
|
|
|
|
*isnull = false;
|
Fix failure to detoast fields in composite elements of structured types.
If we have an array of records stored on disk, the individual record fields
cannot contain out-of-line TOAST pointers: the tuptoaster.c mechanisms are
only prepared to deal with TOAST pointers appearing in top-level fields of
a stored row. The same applies for ranges over composite types, nested
composites, etc. However, the existing code only took care of expanding
sub-field TOAST pointers for the case of nested composites, not for other
structured types containing composites. For example, given a command such
as
UPDATE tab SET arraycol = ARRAY[(ROW(x,42)::mycompositetype] ...
where x is a direct reference to a field of an on-disk tuple, if that field
is long enough to be toasted out-of-line then the TOAST pointer would be
inserted as-is into the array column. If the source record for x is later
deleted, the array field value would become a dangling pointer, leading
to errors along the line of "missing chunk number 0 for toast value ..."
when the value is referenced. A reproducible test case for this was
provided by Jan Pecek, but it seems likely that some of the "missing chunk
number" reports we've heard in the past were caused by similar issues.
Code-wise, the problem is that PG_DETOAST_DATUM() is not adequate to
produce a self-contained Datum value if the Datum is of composite type.
Seen in this light, the problem is not just confined to arrays and ranges,
but could also affect some other places where detoasting is done in that
way, for example form_index_tuple().
I tried teaching the array code to apply toast_flatten_tuple_attribute()
along with PG_DETOAST_DATUM() when the array element type is composite,
but this was messy and imposed extra cache lookup costs whether or not any
TOAST pointers were present, indeed sometimes when the array element type
isn't even composite (since sometimes it takes a typcache lookup to find
that out). The idea of extending that approach to all the places that
currently use PG_DETOAST_DATUM() wasn't attractive at all.
This patch instead solves the problem by decreeing that composite Datum
values must not contain any out-of-line TOAST pointers in the first place;
that is, we expand out-of-line fields at the point of constructing a
composite Datum, not at the point where we're about to insert it into a
larger tuple. This rule is applied only to true composite Datums, not
to tuples that are being passed around the system as tuples, so it's not
as invasive as it might sound at first. With this approach, the amount
of code that has to be touched for a full solution is greatly reduced,
and added cache lookup costs are avoided except when there actually is
a TOAST pointer that needs to be inlined.
The main drawback of this approach is that we might sometimes dereference
a TOAST pointer that will never actually be used by the query, imposing a
rather large cost that wasn't there before. On the other side of the coin,
if the field value is used multiple times then we'll come out ahead by
avoiding repeat detoastings. Experimentation suggests that common SQL
coding patterns are unaffected either way, though. Applications that are
very negatively affected could be advised to modify their code to not fetch
columns they won't be using.
In future, we might consider reverting this solution in favor of detoasting
only at the point where data is about to be stored to disk, using some
method that can drill down into multiple levels of nested structured types.
That will require defining new APIs for structured types, though, so it
doesn't seem feasible as a back-patchable fix.
Note that this patch changes HeapTupleGetDatum() from a macro to a function
call; this means that any third-party code using that macro will not get
protection against creating TOAST-pointer-containing Datums until it's
recompiled. The same applies to any uses of PG_RETURN_HEAPTUPLEHEADER().
It seems likely that this is not a big problem in practice: most of the
tuple-returning functions in core and contrib produce outputs that could
not possibly be toasted anyway, and the same probably holds for third-party
extensions.
This bug has existed since TOAST was invented, so back-patch to all
supported branches.
2014-05-01 21:19:06 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2004-08-29 07:07:03 +02:00
|
|
|
break;
|
|
|
|
}
|
2004-06-04 02:07:52 +02:00
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_REC:
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
|
2004-06-04 02:07:52 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
if (!HeapTupleIsValid(rec->tup))
|
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("record \"%s\" is not assigned yet",
|
|
|
|
rec->refname),
|
|
|
|
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
|
2004-08-29 07:07:03 +02:00
|
|
|
Assert(rec->tupdesc != NULL);
|
|
|
|
/* Make sure we have a valid type/typmod setting */
|
|
|
|
BlessTupleDesc(rec->tupdesc);
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2004-08-29 07:07:03 +02:00
|
|
|
*typeid = rec->tupdesc->tdtypeid;
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
*typetypmod = rec->tupdesc->tdtypmod;
|
Fix failure to detoast fields in composite elements of structured types.
If we have an array of records stored on disk, the individual record fields
cannot contain out-of-line TOAST pointers: the tuptoaster.c mechanisms are
only prepared to deal with TOAST pointers appearing in top-level fields of
a stored row. The same applies for ranges over composite types, nested
composites, etc. However, the existing code only took care of expanding
sub-field TOAST pointers for the case of nested composites, not for other
structured types containing composites. For example, given a command such
as
UPDATE tab SET arraycol = ARRAY[(ROW(x,42)::mycompositetype] ...
where x is a direct reference to a field of an on-disk tuple, if that field
is long enough to be toasted out-of-line then the TOAST pointer would be
inserted as-is into the array column. If the source record for x is later
deleted, the array field value would become a dangling pointer, leading
to errors along the line of "missing chunk number 0 for toast value ..."
when the value is referenced. A reproducible test case for this was
provided by Jan Pecek, but it seems likely that some of the "missing chunk
number" reports we've heard in the past were caused by similar issues.
Code-wise, the problem is that PG_DETOAST_DATUM() is not adequate to
produce a self-contained Datum value if the Datum is of composite type.
Seen in this light, the problem is not just confined to arrays and ranges,
but could also affect some other places where detoasting is done in that
way, for example form_index_tuple().
I tried teaching the array code to apply toast_flatten_tuple_attribute()
along with PG_DETOAST_DATUM() when the array element type is composite,
but this was messy and imposed extra cache lookup costs whether or not any
TOAST pointers were present, indeed sometimes when the array element type
isn't even composite (since sometimes it takes a typcache lookup to find
that out). The idea of extending that approach to all the places that
currently use PG_DETOAST_DATUM() wasn't attractive at all.
This patch instead solves the problem by decreeing that composite Datum
values must not contain any out-of-line TOAST pointers in the first place;
that is, we expand out-of-line fields at the point of constructing a
composite Datum, not at the point where we're about to insert it into a
larger tuple. This rule is applied only to true composite Datums, not
to tuples that are being passed around the system as tuples, so it's not
as invasive as it might sound at first. With this approach, the amount
of code that has to be touched for a full solution is greatly reduced,
and added cache lookup costs are avoided except when there actually is
a TOAST pointer that needs to be inlined.
The main drawback of this approach is that we might sometimes dereference
a TOAST pointer that will never actually be used by the query, imposing a
rather large cost that wasn't there before. On the other side of the coin,
if the field value is used multiple times then we'll come out ahead by
avoiding repeat detoastings. Experimentation suggests that common SQL
coding patterns are unaffected either way, though. Applications that are
very negatively affected could be advised to modify their code to not fetch
columns they won't be using.
In future, we might consider reverting this solution in favor of detoasting
only at the point where data is about to be stored to disk, using some
method that can drill down into multiple levels of nested structured types.
That will require defining new APIs for structured types, though, so it
doesn't seem feasible as a back-patchable fix.
Note that this patch changes HeapTupleGetDatum() from a macro to a function
call; this means that any third-party code using that macro will not get
protection against creating TOAST-pointer-containing Datums until it's
recompiled. The same applies to any uses of PG_RETURN_HEAPTUPLEHEADER().
It seems likely that this is not a big problem in practice: most of the
tuple-returning functions in core and contrib produce outputs that could
not possibly be toasted anyway, and the same probably holds for third-party
extensions.
This bug has existed since TOAST was invented, so back-patch to all
supported branches.
2014-05-01 21:19:06 +02:00
|
|
|
*value = heap_copy_tuple_as_datum(rec->tup, rec->tupdesc);
|
2004-08-29 07:07:03 +02:00
|
|
|
*isnull = false;
|
Fix failure to detoast fields in composite elements of structured types.
If we have an array of records stored on disk, the individual record fields
cannot contain out-of-line TOAST pointers: the tuptoaster.c mechanisms are
only prepared to deal with TOAST pointers appearing in top-level fields of
a stored row. The same applies for ranges over composite types, nested
composites, etc. However, the existing code only took care of expanding
sub-field TOAST pointers for the case of nested composites, not for other
structured types containing composites. For example, given a command such
as
UPDATE tab SET arraycol = ARRAY[(ROW(x,42)::mycompositetype] ...
where x is a direct reference to a field of an on-disk tuple, if that field
is long enough to be toasted out-of-line then the TOAST pointer would be
inserted as-is into the array column. If the source record for x is later
deleted, the array field value would become a dangling pointer, leading
to errors along the line of "missing chunk number 0 for toast value ..."
when the value is referenced. A reproducible test case for this was
provided by Jan Pecek, but it seems likely that some of the "missing chunk
number" reports we've heard in the past were caused by similar issues.
Code-wise, the problem is that PG_DETOAST_DATUM() is not adequate to
produce a self-contained Datum value if the Datum is of composite type.
Seen in this light, the problem is not just confined to arrays and ranges,
but could also affect some other places where detoasting is done in that
way, for example form_index_tuple().
I tried teaching the array code to apply toast_flatten_tuple_attribute()
along with PG_DETOAST_DATUM() when the array element type is composite,
but this was messy and imposed extra cache lookup costs whether or not any
TOAST pointers were present, indeed sometimes when the array element type
isn't even composite (since sometimes it takes a typcache lookup to find
that out). The idea of extending that approach to all the places that
currently use PG_DETOAST_DATUM() wasn't attractive at all.
This patch instead solves the problem by decreeing that composite Datum
values must not contain any out-of-line TOAST pointers in the first place;
that is, we expand out-of-line fields at the point of constructing a
composite Datum, not at the point where we're about to insert it into a
larger tuple. This rule is applied only to true composite Datums, not
to tuples that are being passed around the system as tuples, so it's not
as invasive as it might sound at first. With this approach, the amount
of code that has to be touched for a full solution is greatly reduced,
and added cache lookup costs are avoided except when there actually is
a TOAST pointer that needs to be inlined.
The main drawback of this approach is that we might sometimes dereference
a TOAST pointer that will never actually be used by the query, imposing a
rather large cost that wasn't there before. On the other side of the coin,
if the field value is used multiple times then we'll come out ahead by
avoiding repeat detoastings. Experimentation suggests that common SQL
coding patterns are unaffected either way, though. Applications that are
very negatively affected could be advised to modify their code to not fetch
columns they won't be using.
In future, we might consider reverting this solution in favor of detoasting
only at the point where data is about to be stored to disk, using some
method that can drill down into multiple levels of nested structured types.
That will require defining new APIs for structured types, though, so it
doesn't seem feasible as a back-patchable fix.
Note that this patch changes HeapTupleGetDatum() from a macro to a function
call; this means that any third-party code using that macro will not get
protection against creating TOAST-pointer-containing Datums until it's
recompiled. The same applies to any uses of PG_RETURN_HEAPTUPLEHEADER().
It seems likely that this is not a big problem in practice: most of the
tuple-returning functions in core and contrib produce outputs that could
not possibly be toasted anyway, and the same probably holds for third-party
extensions.
This bug has existed since TOAST was invented, so back-patch to all
supported branches.
2014-05-01 21:19:06 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2004-08-29 07:07:03 +02:00
|
|
|
break;
|
|
|
|
}
|
2003-03-25 01:34:24 +01:00
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_RECFIELD:
|
2004-08-29 07:07:03 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
|
|
|
|
PLpgSQL_rec *rec;
|
2006-05-30 15:40:56 +02:00
|
|
|
int fno;
|
2004-06-04 02:07:52 +02:00
|
|
|
|
2004-08-29 07:07:03 +02:00
|
|
|
rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
|
|
|
|
if (!HeapTupleIsValid(rec->tup))
|
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("record \"%s\" is not assigned yet",
|
|
|
|
rec->refname),
|
|
|
|
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
|
2006-05-30 15:40:56 +02:00
|
|
|
fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
|
|
|
|
if (fno == SPI_ERROR_NOATTRIBUTE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("record \"%s\" has no field \"%s\"",
|
|
|
|
rec->refname, recfield->fieldname)));
|
|
|
|
*typeid = SPI_gettypeid(rec->tupdesc, fno);
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
if (fno > 0)
|
2017-08-20 20:19:07 +02:00
|
|
|
{
|
|
|
|
Form_pg_attribute attr = TupleDescAttr(rec->tupdesc, fno - 1);
|
|
|
|
|
|
|
|
*typetypmod = attr->atttypmod;
|
|
|
|
}
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
else
|
|
|
|
*typetypmod = -1;
|
2006-05-30 15:40:56 +02:00
|
|
|
*value = SPI_getbinval(rec->tup, rec->tupdesc, fno, isnull);
|
2009-11-04 23:26:08 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized dtype: %d", datum->dtype);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2016-03-03 10:45:59 +01:00
|
|
|
* plpgsql_exec_get_datum_type Get datatype of a PLpgSQL_datum
|
2009-11-04 23:26:08 +01:00
|
|
|
*
|
|
|
|
* This is the same logic as in exec_eval_datum, except that it can handle
|
|
|
|
* some cases where exec_eval_datum has to fail; specifically, we may have
|
|
|
|
* a tupdesc but no row value for a record variable. (This currently can
|
|
|
|
* happen only for a trigger's NEW/OLD records.)
|
|
|
|
*/
|
2009-11-06 19:37:55 +01:00
|
|
|
Oid
|
2016-03-03 10:45:59 +01:00
|
|
|
plpgsql_exec_get_datum_type(PLpgSQL_execstate *estate,
|
2016-06-10 00:02:36 +02:00
|
|
|
PLpgSQL_datum *datum)
|
2009-11-04 23:26:08 +01:00
|
|
|
{
|
|
|
|
Oid typeid;
|
|
|
|
|
|
|
|
switch (datum->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_VAR:
|
|
|
|
{
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) datum;
|
|
|
|
|
|
|
|
typeid = var->datatype->typoid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_ROW:
|
|
|
|
{
|
|
|
|
PLpgSQL_row *row = (PLpgSQL_row *) datum;
|
|
|
|
|
|
|
|
if (!row->rowtupdesc) /* should not happen */
|
|
|
|
elog(ERROR, "row variable has no tupdesc");
|
|
|
|
/* Make sure we have a valid type/typmod setting */
|
|
|
|
BlessTupleDesc(row->rowtupdesc);
|
|
|
|
typeid = row->rowtupdesc->tdtypeid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_REC:
|
|
|
|
{
|
|
|
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
|
|
|
|
|
|
|
|
if (rec->tupdesc == NULL)
|
2006-05-30 15:40:56 +02:00
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("record \"%s\" is not assigned yet",
|
|
|
|
rec->refname),
|
|
|
|
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
|
2009-11-04 23:26:08 +01:00
|
|
|
/* Make sure we have a valid type/typmod setting */
|
|
|
|
BlessTupleDesc(rec->tupdesc);
|
|
|
|
typeid = rec->tupdesc->tdtypeid;
|
2006-05-30 15:40:56 +02:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
case PLPGSQL_DTYPE_RECFIELD:
|
2003-03-25 01:34:24 +01:00
|
|
|
{
|
2009-11-04 23:26:08 +01:00
|
|
|
PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
|
|
|
|
PLpgSQL_rec *rec;
|
|
|
|
int fno;
|
2004-08-29 07:07:03 +02:00
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
|
|
|
|
if (rec->tupdesc == NULL)
|
2004-08-29 07:07:03 +02:00
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("record \"%s\" is not assigned yet",
|
|
|
|
rec->refname),
|
|
|
|
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
|
2009-11-04 23:26:08 +01:00
|
|
|
fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
|
|
|
|
if (fno == SPI_ERROR_NOATTRIBUTE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("record \"%s\" has no field \"%s\"",
|
|
|
|
rec->refname, recfield->fieldname)));
|
|
|
|
typeid = SPI_gettypeid(rec->tupdesc, fno);
|
2004-08-29 07:07:03 +02:00
|
|
|
break;
|
2003-03-25 01:34:24 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unrecognized dtype: %d", datum->dtype);
|
2010-02-26 03:01:40 +01:00
|
|
|
typeid = InvalidOid; /* keep compiler quiet */
|
2009-11-04 23:26:08 +01:00
|
|
|
break;
|
2003-03-25 01:34:24 +01:00
|
|
|
}
|
2009-11-04 23:26:08 +01:00
|
|
|
|
|
|
|
return typeid;
|
2003-03-25 01:34:24 +01:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2009-11-06 19:37:55 +01:00
|
|
|
/*
|
2016-03-03 10:45:59 +01:00
|
|
|
* plpgsql_exec_get_datum_type_info Get datatype etc of a PLpgSQL_datum
|
2011-05-22 21:13:35 +02:00
|
|
|
*
|
2016-03-03 10:45:59 +01:00
|
|
|
* An extended version of plpgsql_exec_get_datum_type, which also retrieves the
|
2011-05-22 21:13:35 +02:00
|
|
|
* typmod and collation of the datum.
|
2009-11-06 19:37:55 +01:00
|
|
|
*/
|
2011-05-22 21:13:35 +02:00
|
|
|
void
|
2016-03-03 10:45:59 +01:00
|
|
|
plpgsql_exec_get_datum_type_info(PLpgSQL_execstate *estate,
|
2016-06-10 00:02:36 +02:00
|
|
|
PLpgSQL_datum *datum,
|
|
|
|
Oid *typeid, int32 *typmod, Oid *collation)
|
2009-11-06 19:37:55 +01:00
|
|
|
{
|
2011-03-25 20:06:36 +01:00
|
|
|
switch (datum->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_VAR:
|
|
|
|
{
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) datum;
|
2009-11-06 19:37:55 +01:00
|
|
|
|
2011-05-22 21:13:35 +02:00
|
|
|
*typeid = var->datatype->typoid;
|
|
|
|
*typmod = var->datatype->atttypmod;
|
|
|
|
*collation = var->datatype->collation;
|
2011-03-25 20:06:36 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_ROW:
|
2011-05-22 21:13:35 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_row *row = (PLpgSQL_row *) datum;
|
|
|
|
|
|
|
|
if (!row->rowtupdesc) /* should not happen */
|
|
|
|
elog(ERROR, "row variable has no tupdesc");
|
|
|
|
/* Make sure we have a valid type/typmod setting */
|
|
|
|
BlessTupleDesc(row->rowtupdesc);
|
|
|
|
*typeid = row->rowtupdesc->tdtypeid;
|
|
|
|
/* do NOT return the mutable typmod of a RECORD variable */
|
|
|
|
*typmod = -1;
|
|
|
|
/* composite types are never collatable */
|
|
|
|
*collation = InvalidOid;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2011-03-25 20:06:36 +01:00
|
|
|
case PLPGSQL_DTYPE_REC:
|
2011-05-22 21:13:35 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_rec *rec = (PLpgSQL_rec *) datum;
|
|
|
|
|
|
|
|
if (rec->tupdesc == NULL)
|
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("record \"%s\" is not assigned yet",
|
|
|
|
rec->refname),
|
|
|
|
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
|
2011-05-22 21:13:35 +02:00
|
|
|
/* Make sure we have a valid type/typmod setting */
|
|
|
|
BlessTupleDesc(rec->tupdesc);
|
|
|
|
*typeid = rec->tupdesc->tdtypeid;
|
|
|
|
/* do NOT return the mutable typmod of a RECORD variable */
|
|
|
|
*typmod = -1;
|
|
|
|
/* composite types are never collatable */
|
|
|
|
*collation = InvalidOid;
|
|
|
|
break;
|
|
|
|
}
|
2011-03-25 20:06:36 +01:00
|
|
|
|
|
|
|
case PLPGSQL_DTYPE_RECFIELD:
|
|
|
|
{
|
|
|
|
PLpgSQL_recfield *recfield = (PLpgSQL_recfield *) datum;
|
|
|
|
PLpgSQL_rec *rec;
|
|
|
|
int fno;
|
|
|
|
|
|
|
|
rec = (PLpgSQL_rec *) (estate->datums[recfield->recparentno]);
|
|
|
|
if (rec->tupdesc == NULL)
|
|
|
|
ereport(ERROR,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
|
|
|
|
errmsg("record \"%s\" is not assigned yet",
|
|
|
|
rec->refname),
|
|
|
|
errdetail("The tuple structure of a not-yet-assigned record is indeterminate.")));
|
2011-03-25 20:06:36 +01:00
|
|
|
fno = SPI_fnumber(rec->tupdesc, recfield->fieldname);
|
|
|
|
if (fno == SPI_ERROR_NOATTRIBUTE)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_UNDEFINED_COLUMN),
|
|
|
|
errmsg("record \"%s\" has no field \"%s\"",
|
|
|
|
rec->refname, recfield->fieldname)));
|
2011-05-22 21:13:35 +02:00
|
|
|
*typeid = SPI_gettypeid(rec->tupdesc, fno);
|
|
|
|
if (fno > 0)
|
2017-08-20 20:19:07 +02:00
|
|
|
{
|
|
|
|
Form_pg_attribute attr = TupleDescAttr(rec->tupdesc, fno - 1);
|
|
|
|
|
|
|
|
*typmod = attr->atttypmod;
|
|
|
|
}
|
2011-05-22 21:13:35 +02:00
|
|
|
else
|
|
|
|
*typmod = -1;
|
2011-03-25 20:06:36 +01:00
|
|
|
if (fno > 0)
|
2017-08-20 20:19:07 +02:00
|
|
|
{
|
|
|
|
Form_pg_attribute attr = TupleDescAttr(rec->tupdesc, fno - 1);
|
|
|
|
|
|
|
|
*collation = attr->attcollation;
|
|
|
|
}
|
2017-06-21 20:39:04 +02:00
|
|
|
else /* no system column types have collation */
|
2011-05-22 21:13:35 +02:00
|
|
|
*collation = InvalidOid;
|
2011-03-25 20:06:36 +01:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
default:
|
|
|
|
elog(ERROR, "unrecognized dtype: %d", datum->dtype);
|
Phase 2 of pgindent updates.
Change pg_bsd_indent to follow upstream rules for placement of comments
to the right of code, and remove pgindent hack that caused comments
following #endif to not obey the general rule.
Commit e3860ffa4dd0dad0dd9eea4be9cc1412373a8c89 wasn't actually using
the published version of pg_bsd_indent, but a hacked-up version that
tried to minimize the amount of movement of comments to the right of
code. The situation of interest is where such a comment has to be
moved to the right of its default placement at column 33 because there's
code there. BSD indent has always moved right in units of tab stops
in such cases --- but in the previous incarnation, indent was working
in 8-space tab stops, while now it knows we use 4-space tabs. So the
net result is that in about half the cases, such comments are placed
one tab stop left of before. This is better all around: it leaves
more room on the line for comment text, and it means that in such
cases the comment uniformly starts at the next 4-space tab stop after
the code, rather than sometimes one and sometimes two tabs after.
Also, ensure that comments following #endif are indented the same
as comments following other preprocessor commands such as #else.
That inconsistency turns out to have been self-inflicted damage
from a poorly-thought-through post-indent "fixup" in pgindent.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:18:54 +02:00
|
|
|
*typeid = InvalidOid; /* keep compiler quiet */
|
2011-05-22 21:13:35 +02:00
|
|
|
*typmod = -1;
|
|
|
|
*collation = InvalidOid;
|
2011-03-25 20:06:36 +01:00
|
|
|
break;
|
|
|
|
}
|
2009-11-06 19:37:55 +01:00
|
|
|
}
|
|
|
|
|
2003-03-25 04:16:41 +01:00
|
|
|
/* ----------
|
2003-09-29 01:37:45 +02:00
|
|
|
* exec_eval_integer Evaluate an expression, coerce result to int4
|
2003-03-25 04:16:41 +01:00
|
|
|
*
|
2003-09-29 01:37:45 +02:00
|
|
|
* Note we do not do exec_eval_cleanup here; the caller must do it at
|
|
|
|
* some later point. (We do this because the caller may be holding the
|
|
|
|
* results of other, pass-by-reference, expression evaluations, such as
|
2015-03-14 22:07:01 +01:00
|
|
|
* an array value to be subscripted.)
|
2003-03-25 04:16:41 +01:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_eval_integer(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *expr,
|
2003-09-29 01:37:45 +02:00
|
|
|
bool *isNull)
|
2003-03-25 04:16:41 +01:00
|
|
|
{
|
2003-09-29 01:37:45 +02:00
|
|
|
Datum exprdatum;
|
|
|
|
Oid exprtypeid;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 exprtypmod;
|
2003-03-25 04:16:41 +01:00
|
|
|
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
exprdatum = exec_cast_value(estate, exprdatum, isNull,
|
|
|
|
exprtypeid, exprtypmod,
|
|
|
|
INT4OID, -1);
|
2003-09-29 01:37:45 +02:00
|
|
|
return DatumGetInt32(exprdatum);
|
2003-03-25 04:16:41 +01:00
|
|
|
}
|
|
|
|
|
2003-10-01 23:47:42 +02:00
|
|
|
/* ----------
|
|
|
|
* exec_eval_boolean Evaluate an expression, coerce result to bool
|
|
|
|
*
|
|
|
|
* Note we do not do exec_eval_cleanup here; the caller must do it at
|
|
|
|
* some later point.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static bool
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_eval_boolean(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *expr,
|
2003-10-01 23:47:42 +02:00
|
|
|
bool *isNull)
|
|
|
|
{
|
|
|
|
Datum exprdatum;
|
|
|
|
Oid exprtypeid;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 exprtypmod;
|
2003-10-01 23:47:42 +02:00
|
|
|
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
exprdatum = exec_eval_expr(estate, expr, isNull, &exprtypeid, &exprtypmod);
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
exprdatum = exec_cast_value(estate, exprdatum, isNull,
|
|
|
|
exprtypeid, exprtypmod,
|
|
|
|
BOOLOID, -1);
|
2003-10-01 23:47:42 +02:00
|
|
|
return DatumGetBool(exprdatum);
|
|
|
|
}
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
|
|
|
* exec_eval_expr Evaluate an expression and return
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
* the result Datum, along with data type/typmod.
|
2001-08-02 23:31:23 +02:00
|
|
|
*
|
|
|
|
* NOTE: caller must do exec_eval_cleanup when done with the Datum.
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static Datum
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_eval_expr(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *expr,
|
1998-09-01 06:40:42 +02:00
|
|
|
bool *isNull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Oid *rettype,
|
|
|
|
int32 *rettypmod)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2008-05-16 20:34:51 +02:00
|
|
|
Datum result = 0;
|
1998-09-01 06:40:42 +02:00
|
|
|
int rc;
|
2017-08-20 20:19:07 +02:00
|
|
|
Form_pg_attribute attr;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2007-03-16 00:12:07 +01:00
|
|
|
* If first time through, create a plan for this expression.
|
1999-01-27 17:15:22 +01:00
|
|
|
*/
|
|
|
|
if (expr->plan == NULL)
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK);
|
2006-05-30 15:40:56 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* If this is a simple expression, bypass SPI and use the executor
|
|
|
|
* directly
|
1999-01-27 17:15:22 +01:00
|
|
|
*/
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
if (exec_eval_simple_expr(estate, expr,
|
|
|
|
&result, isNull, rettype, rettypmod))
|
2007-03-16 00:12:07 +01:00
|
|
|
return result;
|
1999-01-27 17:15:22 +01:00
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
/*
|
|
|
|
* Else do it the hard way via exec_run_select
|
|
|
|
*/
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
rc = exec_run_select(estate, expr, 2, NULL);
|
1998-09-01 06:40:42 +02:00
|
|
|
if (rc != SPI_OK_SELECT)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("query \"%s\" did not return data", expr->query)));
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2010-04-15 01:52:10 +02:00
|
|
|
* Check that the expression returns exactly one column...
|
|
|
|
*/
|
|
|
|
if (estate->eval_tuptable->tupdesc->natts != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg_plural("query \"%s\" returned %d column",
|
|
|
|
"query \"%s\" returned %d columns",
|
|
|
|
estate->eval_tuptable->tupdesc->natts,
|
|
|
|
expr->query,
|
|
|
|
estate->eval_tuptable->tupdesc->natts)));
|
|
|
|
|
|
|
|
/*
|
|
|
|
* ... and get the column's datatype.
|
|
|
|
*/
|
2017-08-20 20:19:07 +02:00
|
|
|
attr = TupleDescAttr(estate->eval_tuptable->tupdesc, 0);
|
|
|
|
*rettype = attr->atttypid;
|
|
|
|
*rettypmod = attr->atttypmod;
|
2010-04-15 01:52:10 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If there are no rows selected, the result is a NULL of that type.
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2001-08-02 23:31:23 +02:00
|
|
|
if (estate->eval_processed == 0)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
|
|
|
*isNull = true;
|
|
|
|
return (Datum) 0;
|
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2010-04-15 01:52:10 +02:00
|
|
|
* Check that the expression returned no more than one row.
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2010-04-15 01:52:10 +02:00
|
|
|
if (estate->eval_processed != 1)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_CARDINALITY_VIOLATION),
|
|
|
|
errmsg("query \"%s\" returned more than one row",
|
|
|
|
expr->query)));
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2010-04-15 01:52:10 +02:00
|
|
|
* Return the single result Datum.
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2001-08-02 23:31:23 +02:00
|
|
|
return SPI_getbinval(estate->eval_tuptable->vals[0],
|
|
|
|
estate->eval_tuptable->tupdesc, 1, isNull);
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_run_select Execute a select query
|
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static int
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_run_select(PLpgSQL_execstate *estate,
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
PLpgSQL_expr *expr, long maxtuples, Portal *portalP)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2009-11-04 23:26:08 +01:00
|
|
|
ParamListInfo paramLI;
|
1998-09-01 06:40:42 +02:00
|
|
|
int rc;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
* On the first call for this expression generate the plan.
|
|
|
|
*
|
|
|
|
* If we don't need to return a portal, then we're just going to execute
|
|
|
|
* the query once, which means it's OK to use a parallel plan, even if the
|
|
|
|
* number of rows being fetched is limited. If we do need to return a
|
|
|
|
* portal, the caller might do cursor operations, which parallel query
|
|
|
|
* can't support.
|
1998-08-22 14:38:39 +02:00
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
if (expr->plan == NULL)
|
Improve access to parallel query from procedural languages.
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism. Remove that condition.
SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion. Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that. This improves access to
parallelism for any caller that uses these functions to execute
queries. Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.
In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).
Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila
Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com
2017-03-24 19:46:33 +01:00
|
|
|
exec_prepare_plan(estate, expr,
|
|
|
|
portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0);
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-08-02 23:31:23 +02:00
|
|
|
* If a portal was requested, put the query into the portal
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
2001-05-21 16:22:19 +02:00
|
|
|
if (portalP != NULL)
|
|
|
|
{
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/*
|
|
|
|
* Set up short-lived ParamListInfo
|
|
|
|
*/
|
|
|
|
paramLI = setup_unshared_param_list(estate, expr);
|
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
*portalP = SPI_cursor_open_with_paramlist(NULL, expr->plan,
|
|
|
|
paramLI,
|
|
|
|
estate->readonly_func);
|
2001-05-21 16:22:19 +02:00
|
|
|
if (*portalP == NULL)
|
2004-07-31 22:55:45 +02:00
|
|
|
elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
|
|
|
|
expr->query, SPI_result_code_string(SPI_result));
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
exec_eval_cleanup(estate);
|
2001-05-21 16:22:19 +02:00
|
|
|
return SPI_OK_CURSOR;
|
|
|
|
}
|
2001-08-02 23:31:23 +02:00
|
|
|
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/*
|
|
|
|
* Set up ParamListInfo to pass to executor
|
|
|
|
*/
|
|
|
|
paramLI = setup_param_list(estate, expr);
|
|
|
|
|
2001-08-02 23:31:23 +02:00
|
|
|
/*
|
|
|
|
* Execute the query
|
|
|
|
*/
|
2009-11-04 23:26:08 +01:00
|
|
|
rc = SPI_execute_plan_with_paramlist(expr->plan, paramLI,
|
|
|
|
estate->readonly_func, maxtuples);
|
1998-09-01 06:40:42 +02:00
|
|
|
if (rc != SPI_OK_SELECT)
|
2003-07-26 01:37:31 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
errmsg("query \"%s\" is not a SELECT", expr->query)));
|
2001-08-02 23:31:23 +02:00
|
|
|
|
|
|
|
/* Save query results for eventual cleanup */
|
|
|
|
Assert(estate->eval_tuptable == NULL);
|
|
|
|
estate->eval_tuptable = SPI_tuptable;
|
|
|
|
estate->eval_processed = SPI_processed;
|
|
|
|
estate->eval_lastoid = SPI_lastoid;
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return rc;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
|
|
|
* exec_for_query --- execute body of FOR loop for each row from a portal
|
|
|
|
*
|
|
|
|
* Used by exec_stmt_fors, exec_stmt_forc and exec_stmt_dynfors
|
|
|
|
*/
|
|
|
|
static int
|
|
|
|
exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
|
|
|
|
Portal portal, bool prefetch_ok)
|
|
|
|
{
|
|
|
|
PLpgSQL_rec *rec = NULL;
|
|
|
|
PLpgSQL_row *row = NULL;
|
|
|
|
SPITupleTable *tuptab;
|
|
|
|
bool found = false;
|
|
|
|
int rc = PLPGSQL_RC_OK;
|
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 n;
|
2008-04-07 01:43:29 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine if we assign to a record or a row
|
|
|
|
*/
|
|
|
|
if (stmt->rec != NULL)
|
2008-11-05 01:07:54 +01:00
|
|
|
rec = (PLpgSQL_rec *) (estate->datums[stmt->rec->dno]);
|
2008-04-07 01:43:29 +02:00
|
|
|
else if (stmt->row != NULL)
|
2008-11-05 01:07:54 +01:00
|
|
|
row = (PLpgSQL_row *) (estate->datums[stmt->row->dno]);
|
2008-04-07 01:43:29 +02:00
|
|
|
else
|
|
|
|
elog(ERROR, "unsupported target");
|
|
|
|
|
2010-07-05 11:27:18 +02:00
|
|
|
/*
|
2010-07-06 21:19:02 +02:00
|
|
|
* Make sure the portal doesn't get closed by the user statements we
|
|
|
|
* execute.
|
2010-07-05 11:27:18 +02:00
|
|
|
*/
|
|
|
|
PinPortal(portal);
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Fetch the initial tuple(s). If prefetching is allowed then we grab a
|
2009-06-11 16:49:15 +02:00
|
|
|
* few more rows to avoid multiple trips through executor startup
|
2008-04-07 01:43:29 +02:00
|
|
|
* overhead.
|
|
|
|
*/
|
|
|
|
SPI_cursor_fetch(portal, true, prefetch_ok ? 10 : 1);
|
|
|
|
tuptab = SPI_tuptable;
|
|
|
|
n = SPI_processed;
|
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If the query didn't return any rows, set the target to NULL and fall
|
|
|
|
* through with found = false.
|
2008-04-07 01:43:29 +02:00
|
|
|
*/
|
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
|
|
|
if (n == 0)
|
2012-02-12 00:06:24 +01:00
|
|
|
{
|
2008-04-07 01:43:29 +02:00
|
|
|
exec_move_row(estate, rec, row, NULL, tuptab->tupdesc);
|
2012-02-12 00:06:24 +01:00
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
}
|
2008-04-07 01:43:29 +02:00
|
|
|
else
|
|
|
|
found = true; /* processed at least one tuple */
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now do the loop
|
|
|
|
*/
|
|
|
|
while (n > 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
|
|
|
uint64 i;
|
2008-04-07 01:43:29 +02:00
|
|
|
|
|
|
|
for (i = 0; i < n; i++)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Assign the tuple to the target
|
|
|
|
*/
|
|
|
|
exec_move_row(estate, rec, row, tuptab->vals[i], tuptab->tupdesc);
|
2012-02-12 00:06:24 +01:00
|
|
|
exec_eval_cleanup(estate);
|
2008-04-07 01:43:29 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Execute the statements
|
|
|
|
*/
|
|
|
|
rc = exec_stmts(estate, stmt->body);
|
|
|
|
|
|
|
|
if (rc != PLPGSQL_RC_OK)
|
|
|
|
{
|
|
|
|
if (rc == PLPGSQL_RC_EXIT)
|
|
|
|
{
|
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
{
|
|
|
|
/* unlabelled exit, so exit the current loop */
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
else if (stmt->label != NULL &&
|
|
|
|
strcmp(stmt->label, estate->exitlabel) == 0)
|
|
|
|
{
|
|
|
|
/* label matches this loop, so exit loop */
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* otherwise, we processed a labelled exit that does not
|
|
|
|
* match the current statement's label, if any; return
|
|
|
|
* RC_EXIT so that the EXIT continues to recurse upward.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
else if (rc == PLPGSQL_RC_CONTINUE)
|
|
|
|
{
|
|
|
|
if (estate->exitlabel == NULL)
|
|
|
|
{
|
|
|
|
/* unlabelled continue, so re-run the current loop */
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
else if (stmt->label != NULL &&
|
|
|
|
strcmp(stmt->label, estate->exitlabel) == 0)
|
|
|
|
{
|
|
|
|
/* label matches this loop, so re-run loop */
|
|
|
|
estate->exitlabel = NULL;
|
|
|
|
rc = PLPGSQL_RC_OK;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* otherwise, we process a labelled continue that does not
|
|
|
|
* match the current statement's label, if any; return
|
|
|
|
* RC_CONTINUE so that the CONTINUE will propagate up the
|
|
|
|
* stack.
|
|
|
|
*/
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We're aborting the loop. Need a goto to get out of two
|
|
|
|
* levels of loop...
|
|
|
|
*/
|
|
|
|
goto loop_exit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
SPI_freetuptable(tuptab);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Fetch more tuples. If prefetching is allowed, grab 50 at a time.
|
|
|
|
*/
|
2010-07-05 11:27:18 +02:00
|
|
|
SPI_cursor_fetch(portal, true, prefetch_ok ? 50 : 1);
|
2008-04-07 01:43:29 +02:00
|
|
|
tuptab = SPI_tuptable;
|
|
|
|
n = SPI_processed;
|
|
|
|
}
|
|
|
|
|
|
|
|
loop_exit:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Release last group of tuples (if any)
|
|
|
|
*/
|
|
|
|
SPI_freetuptable(tuptab);
|
|
|
|
|
2010-07-05 11:27:18 +02:00
|
|
|
UnpinPortal(portal);
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
|
|
|
* Set the FOUND variable to indicate the result of executing the loop
|
|
|
|
* (namely, whether we looped one or more times). This must be set last so
|
|
|
|
* that it does not interfere with the value of the FOUND variable inside
|
|
|
|
* the loop processing itself.
|
|
|
|
*/
|
|
|
|
exec_set_found(estate, found);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-01-27 17:15:22 +01:00
|
|
|
/* ----------
|
|
|
|
* exec_eval_simple_expr - Evaluate a simple expression returning
|
|
|
|
* a Datum by directly calling ExecEvalExpr().
|
2003-09-29 01:37:45 +02:00
|
|
|
*
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
* If successful, store results into *result, *isNull, *rettype, *rettypmod
|
|
|
|
* and return TRUE. If the expression cannot be handled by simple evaluation,
|
2010-10-28 19:00:54 +02:00
|
|
|
* return FALSE.
|
|
|
|
*
|
|
|
|
* Because we only store one execution tree for a simple expression, we
|
|
|
|
* can't handle recursion cases. So, if we see the tree is already busy
|
|
|
|
* with an evaluation in the current xact, we just return FALSE and let the
|
2014-05-06 18:12:18 +02:00
|
|
|
* caller run the expression the hard way. (Other alternatives such as
|
2010-10-28 19:00:54 +02:00
|
|
|
* creating a new tree for a recursive call either introduce memory leaks,
|
|
|
|
* or add enough bookkeeping to be doubtful wins anyway.) Another case that
|
|
|
|
* is covered by the expr_simple_in_use test is where a previous execution
|
|
|
|
* of the tree was aborted by an error: the tree may contain bogus state
|
|
|
|
* so we dare not re-use it.
|
2007-03-16 00:12:07 +01:00
|
|
|
*
|
2017-08-15 18:28:39 +02:00
|
|
|
* It is possible that we'd need to replan a simple expression; for example,
|
|
|
|
* someone might redefine a SQL function that had been inlined into the simple
|
|
|
|
* expression. That cannot cause a simple expression to become non-simple (or
|
|
|
|
* vice versa), but we do have to handle replacing the expression tree.
|
|
|
|
* Fortunately it's normally inexpensive to call SPI_plan_get_cached_plan for
|
|
|
|
* a simple expression.
|
2007-03-16 00:12:07 +01:00
|
|
|
*
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* Note: if pass-by-reference, the result is in the eval_mcontext.
|
|
|
|
* It will be freed when exec_eval_cleanup is done.
|
1999-01-27 17:15:22 +01:00
|
|
|
* ----------
|
|
|
|
*/
|
2007-03-16 00:12:07 +01:00
|
|
|
static bool
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_eval_simple_expr(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *expr,
|
2007-03-16 00:12:07 +01:00
|
|
|
Datum *result,
|
1999-05-25 18:15:34 +02:00
|
|
|
bool *isNull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Oid *rettype,
|
|
|
|
int32 *rettypmod)
|
1999-01-27 17:15:22 +01:00
|
|
|
{
|
2005-06-21 00:51:29 +02:00
|
|
|
ExprContext *econtext = estate->eval_econtext;
|
2009-04-09 04:57:53 +02:00
|
|
|
LocalTransactionId curlxid = MyProc->lxid;
|
2007-03-16 00:12:07 +01:00
|
|
|
CachedPlan *cplan;
|
1999-01-27 17:15:22 +01:00
|
|
|
ParamListInfo paramLI;
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
void *save_setup_arg;
|
2008-05-12 22:02:02 +02:00
|
|
|
MemoryContext oldcontext;
|
2003-09-29 01:37:45 +02:00
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
/*
|
|
|
|
* Forget it if expression wasn't simple before.
|
|
|
|
*/
|
|
|
|
if (expr->expr_simple_expr == NULL)
|
|
|
|
return false;
|
|
|
|
|
2010-10-28 19:00:54 +02:00
|
|
|
/*
|
|
|
|
* If expression is in use in current xact, don't touch it.
|
|
|
|
*/
|
|
|
|
if (expr->expr_simple_in_use && expr->expr_simple_lxid == curlxid)
|
|
|
|
return false;
|
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Revalidate cached plan, so that we will notice if it became stale. (We
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* need to hold a refcount while using the plan, anyway.) If replanning
|
|
|
|
* is needed, do that work in the eval_mcontext.
|
2007-03-16 00:12:07 +01:00
|
|
|
*/
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
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
|
|
|
cplan = SPI_plan_get_cached_plan(expr->plan);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2011-09-16 06:42:53 +02: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
|
|
|
/*
|
|
|
|
* We can't get a failure here, because the number of CachedPlanSources in
|
|
|
|
* the SPI plan can't change from what exec_simple_check_plan saw; it's a
|
|
|
|
* property of the raw parsetree generated from the query text.
|
|
|
|
*/
|
|
|
|
Assert(cplan != NULL);
|
2011-09-16 06:42:53 +02:00
|
|
|
|
2017-08-15 18:28:39 +02:00
|
|
|
/* If it got replanned, update our copy of the simple expression */
|
2007-03-16 00:12:07 +01:00
|
|
|
if (cplan->generation != expr->expr_simple_generation)
|
|
|
|
{
|
2017-08-15 18:28:39 +02:00
|
|
|
exec_save_simple_expr(expr, cplan);
|
|
|
|
/* better recheck r/w safety, as it could change due to inlining */
|
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
|
|
|
if (expr->rwparam >= 0)
|
|
|
|
exec_check_rw_parameter(expr, expr->rwparam);
|
2007-03-16 00:12:07 +01:00
|
|
|
}
|
|
|
|
|
2003-09-29 01:37:45 +02:00
|
|
|
/*
|
|
|
|
* Pass back previously-determined result type.
|
|
|
|
*/
|
|
|
|
*rettype = expr->expr_simple_type;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
*rettypmod = expr->expr_simple_typmod;
|
2003-09-29 01:37:45 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Prepare the expression for execution, if it's not been done already in
|
2009-04-09 04:57:53 +02:00
|
|
|
* the current transaction. (This will be forced to happen if we called
|
2017-08-15 18:28:39 +02:00
|
|
|
* exec_save_simple_expr above.)
|
2003-09-29 01:37:45 +02:00
|
|
|
*/
|
2009-04-09 04:57:53 +02:00
|
|
|
if (expr->expr_simple_lxid != curlxid)
|
2003-09-29 01:37:45 +02:00
|
|
|
{
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
|
2010-10-28 19:29:13 +02:00
|
|
|
expr->expr_simple_state = ExecInitExpr(expr->expr_simple_expr, NULL);
|
2010-10-28 19:00:54 +02:00
|
|
|
expr->expr_simple_in_use = false;
|
2009-04-09 04:57:53 +02:00
|
|
|
expr->expr_simple_lxid = curlxid;
|
2010-10-28 19:29:13 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2003-09-29 01:37:45 +02:00
|
|
|
}
|
1999-01-27 17:15:22 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* We have to do some of the things SPI_execute_plan would do, in
|
|
|
|
* particular advance the snapshot if we are in a non-read-only function.
|
|
|
|
* Without this, stable functions within the expression would fail to see
|
|
|
|
* updates made so far by our own function.
|
1999-01-27 17:15:22 +01:00
|
|
|
*/
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2008-05-12 22:02:02 +02:00
|
|
|
if (!estate->readonly_func)
|
2004-12-19 21:20:27 +01:00
|
|
|
{
|
2008-05-12 22:02:02 +02:00
|
|
|
CommandCounterIncrement();
|
|
|
|
PushActiveSnapshot(GetTransactionSnapshot());
|
|
|
|
}
|
2004-12-19 21:20:27 +01:00
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
/*
|
2015-08-18 01:39:35 +02:00
|
|
|
* Set up ParamListInfo to pass to executor. We need an unshared list if
|
|
|
|
* it's going to include any R/W expanded-object pointer. For safety,
|
|
|
|
* save and restore estate->paramLI->parserSetupArg around our use of the
|
|
|
|
* param list.
|
2009-11-04 23:26:08 +01:00
|
|
|
*/
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
save_setup_arg = estate->paramLI->parserSetupArg;
|
2009-11-04 23:26:08 +01:00
|
|
|
|
2015-08-18 01:39:35 +02:00
|
|
|
if (expr->rwparam >= 0)
|
|
|
|
paramLI = setup_unshared_param_list(estate, expr);
|
|
|
|
else
|
|
|
|
paramLI = setup_param_list(estate, expr);
|
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
econtext->ecxt_param_list_info = paramLI;
|
|
|
|
|
2010-10-28 19:00:54 +02:00
|
|
|
/*
|
|
|
|
* Mark expression as busy for the duration of the ExecEvalExpr call.
|
|
|
|
*/
|
|
|
|
expr->expr_simple_in_use = true;
|
|
|
|
|
2008-05-12 22:02:02 +02:00
|
|
|
/*
|
|
|
|
* Finally we can call the executor to evaluate the expression
|
|
|
|
*/
|
|
|
|
*result = ExecEvalExpr(expr->expr_simple_state,
|
|
|
|
econtext,
|
2017-01-19 23:12:38 +01:00
|
|
|
isNull);
|
2009-11-04 23:26:08 +01:00
|
|
|
|
|
|
|
/* Assorted cleanup */
|
2010-10-28 19:00:54 +02:00
|
|
|
expr->expr_simple_in_use = false;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
econtext->ecxt_param_list_info = NULL;
|
2015-08-18 01:39:35 +02:00
|
|
|
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
estate->paramLI->parserSetupArg = save_setup_arg;
|
2004-12-21 19:33:36 +01:00
|
|
|
|
2008-05-12 22:02:02 +02:00
|
|
|
if (!estate->readonly_func)
|
|
|
|
PopActiveSnapshot();
|
2004-12-19 21:20:27 +01:00
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
/*
|
|
|
|
* Now we can release our refcount on the cached plan.
|
|
|
|
*/
|
|
|
|
ReleaseCachedPlan(cplan, true);
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
1999-01-27 17:15:22 +01:00
|
|
|
* That's it.
|
|
|
|
*/
|
2007-03-16 00:12:07 +01:00
|
|
|
return true;
|
1999-01-27 17:15:22 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
2009-11-04 23:26:08 +01:00
|
|
|
* Create a ParamListInfo to pass to SPI
|
|
|
|
*
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
* We share a single ParamListInfo array across all SPI calls made from this
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* estate, except calls creating cursors, which use setup_unshared_param_list
|
2015-08-18 01:39:35 +02:00
|
|
|
* (see its comments for reasons why), and calls that pass a R/W expanded
|
|
|
|
* object pointer. A shared array is generally OK since any given slot in
|
|
|
|
* the array would need to contain the same current datum value no matter
|
|
|
|
* which query or expression we're evaluating; but of course that doesn't
|
|
|
|
* hold when a specific variable is being passed as a R/W pointer, because
|
|
|
|
* other expressions in the same function probably don't want to do that.
|
|
|
|
*
|
|
|
|
* Note that paramLI->parserSetupArg points to the specific PLpgSQL_expr
|
|
|
|
* being evaluated. This is not an issue for statement-level callers, but
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* lower-level callers must save and restore estate->paramLI->parserSetupArg
|
|
|
|
* just in case there's an active evaluation at an outer call level.
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* The general plan for passing parameters to SPI is that plain VAR datums
|
|
|
|
* always have valid images in the shared param list. This is ensured by
|
|
|
|
* assign_simple_var(), which also marks those params as PARAM_FLAG_CONST,
|
|
|
|
* allowing the planner to use those values in custom plans. However, non-VAR
|
|
|
|
* datums cannot conveniently be managed that way. For one thing, they could
|
|
|
|
* throw errors (for example "no such record field") and we do not want that
|
|
|
|
* to happen in a part of the expression that might never be evaluated at
|
|
|
|
* runtime. For another thing, exec_eval_datum() may return short-lived
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* values stored in the estate's eval_mcontext, which will not necessarily
|
|
|
|
* survive to the next SPI operation. And for a third thing, ROW
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* and RECFIELD datums' values depend on other datums, and we don't have a
|
|
|
|
* cheap way to track that. Therefore, param slots for non-VAR datum types
|
|
|
|
* are always reset here and then filled on-demand by plpgsql_param_fetch().
|
|
|
|
* We can save a few cycles by not bothering with the reset loop unless at
|
|
|
|
* least one such param has actually been filled by plpgsql_param_fetch().
|
2008-04-07 01:43:29 +02:00
|
|
|
*/
|
2009-11-04 23:26:08 +01:00
|
|
|
static ParamListInfo
|
|
|
|
setup_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
|
2008-04-07 01:43:29 +02:00
|
|
|
{
|
2009-11-04 23:26:08 +01:00
|
|
|
ParamListInfo paramLI;
|
2008-04-07 01:43:29 +02:00
|
|
|
|
2011-09-16 18:31:23 +02:00
|
|
|
/*
|
|
|
|
* We must have created the SPIPlan already (hence, query text has been
|
|
|
|
* parsed/analyzed at least once); else we cannot rely on expr->paramnos.
|
|
|
|
*/
|
|
|
|
Assert(expr->plan != NULL);
|
|
|
|
|
2015-08-18 01:39:35 +02:00
|
|
|
/*
|
|
|
|
* Expressions with R/W parameters can't use the shared param list.
|
|
|
|
*/
|
|
|
|
Assert(expr->rwparam == -1);
|
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
/*
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
* We only need a ParamListInfo if the expression has parameters. In
|
|
|
|
* principle we should test with bms_is_empty(), but we use a not-null
|
|
|
|
* test because it's faster. In current usage bits are never removed from
|
|
|
|
* expr->paramnos, only added, so this test is correct anyway.
|
2009-11-04 23:26:08 +01:00
|
|
|
*/
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
if (expr->paramnos)
|
2008-04-07 01:43:29 +02:00
|
|
|
{
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/* Use the common ParamListInfo */
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
paramLI = estate->paramLI;
|
|
|
|
|
|
|
|
/*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* If any resettable parameters have been passed to the executor since
|
|
|
|
* last time, we need to reset those param slots to "invalid", for the
|
|
|
|
* reasons mentioned in the comment above.
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
*/
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
if (estate->params_dirty)
|
|
|
|
{
|
|
|
|
Bitmapset *resettable_datums = estate->func->resettable_datums;
|
|
|
|
int dno = -1;
|
|
|
|
|
|
|
|
while ((dno = bms_next_member(resettable_datums, dno)) >= 0)
|
|
|
|
{
|
|
|
|
ParamExternData *prm = ¶mLI->params[dno];
|
|
|
|
|
|
|
|
prm->ptype = InvalidOid;
|
|
|
|
}
|
|
|
|
estate->params_dirty = false;
|
|
|
|
}
|
2009-11-04 23:26:08 +01:00
|
|
|
|
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
|
|
|
/*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* Set up link to active expr where the hook functions can find it.
|
|
|
|
* Callers must save and restore parserSetupArg if there is any chance
|
|
|
|
* that they are interrupting an active use of parameters.
|
|
|
|
*/
|
|
|
|
paramLI->parserSetupArg = (void *) expr;
|
|
|
|
|
Fix problems with ParamListInfo serialization mechanism.
Commit d1b7c1ffe72e86932b5395f29e006c3f503bc53d introduced a mechanism
for serializing a ParamListInfo structure to be passed to a parallel
worker. However, this mechanism failed to handle external expanded
values, as pointed out by Noah Misch. Repair.
Moreover, plpgsql_param_fetch requires adjustment because the
serialization mechanism needs it to skip evaluating unused parameters
just as we would do when it is called from copyParamList, but params
== estate->paramLI in that case. To fix, make the bms_is_member test
in that function unconditional.
Finally, have setup_param_list set a new ParamListInfo field,
paramMask, to the parameters actually used in the expression, so that
we don't try to fetch those that are not needed when serializing a
parameter list. This isn't necessary for correctness, but it makes
the performance of the parallel executor code comparable to what we
do for cases involving cursors.
Design suggestions and extensive review by Noah Misch. Patch by me.
2015-11-03 00:11:29 +01:00
|
|
|
/*
|
|
|
|
* Allow parameters that aren't needed by this expression to be
|
|
|
|
* ignored.
|
|
|
|
*/
|
|
|
|
paramLI->paramMask = expr->paramnos;
|
|
|
|
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/*
|
|
|
|
* Also make sure this is set before parser hooks need it. There is
|
|
|
|
* no need to save and restore, since the value is always correct once
|
|
|
|
* set. (Should be set already, but let's be sure.)
|
|
|
|
*/
|
|
|
|
expr->func = estate->func;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Expression requires no parameters. Be sure we represent this case
|
|
|
|
* as a NULL ParamListInfo, so that plancache.c knows there is no
|
|
|
|
* point in a custom plan.
|
|
|
|
*/
|
|
|
|
paramLI = NULL;
|
|
|
|
}
|
|
|
|
return paramLI;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Create an unshared, short-lived ParamListInfo to pass to SPI
|
|
|
|
*
|
|
|
|
* When creating a cursor, we do not use the shared ParamListInfo array
|
|
|
|
* but create a short-lived one that will contain only params actually
|
|
|
|
* referenced by the query. The reason for this is that copyParamList() will
|
|
|
|
* be used to copy the parameters into cursor-lifespan storage, and we don't
|
|
|
|
* want it to copy anything that's not used by the specific cursor; that
|
|
|
|
* could result in uselessly copying some large values.
|
|
|
|
*
|
2015-08-18 01:39:35 +02:00
|
|
|
* We also use this for expressions that are passing a R/W object pointer
|
|
|
|
* to some trusted function. We don't want the R/W pointer to get into the
|
|
|
|
* shared param list, where it could get passed to some less-trusted function.
|
|
|
|
*
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* The result, if not NULL, is in the estate's eval_mcontext.
|
Fix problems with ParamListInfo serialization mechanism.
Commit d1b7c1ffe72e86932b5395f29e006c3f503bc53d introduced a mechanism
for serializing a ParamListInfo structure to be passed to a parallel
worker. However, this mechanism failed to handle external expanded
values, as pointed out by Noah Misch. Repair.
Moreover, plpgsql_param_fetch requires adjustment because the
serialization mechanism needs it to skip evaluating unused parameters
just as we would do when it is called from copyParamList, but params
== estate->paramLI in that case. To fix, make the bms_is_member test
in that function unconditional.
Finally, have setup_param_list set a new ParamListInfo field,
paramMask, to the parameters actually used in the expression, so that
we don't try to fetch those that are not needed when serializing a
parameter list. This isn't necessary for correctness, but it makes
the performance of the parallel executor code comparable to what we
do for cases involving cursors.
Design suggestions and extensive review by Noah Misch. Patch by me.
2015-11-03 00:11:29 +01:00
|
|
|
*
|
|
|
|
* XXX. Could we use ParamListInfo's new paramMask to avoid creating unshared
|
|
|
|
* parameter lists?
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
*/
|
|
|
|
static ParamListInfo
|
|
|
|
setup_unshared_param_list(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
|
|
|
|
{
|
|
|
|
ParamListInfo paramLI;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We must have created the SPIPlan already (hence, query text has been
|
|
|
|
* parsed/analyzed at least once); else we cannot rely on expr->paramnos.
|
|
|
|
*/
|
|
|
|
Assert(expr->plan != NULL);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We only need a ParamListInfo if the expression has parameters. In
|
|
|
|
* principle we should test with bms_is_empty(), but we use a not-null
|
|
|
|
* test because it's faster. In current usage bits are never removed from
|
|
|
|
* expr->paramnos, only added, so this test is correct anyway.
|
|
|
|
*/
|
|
|
|
if (expr->paramnos)
|
|
|
|
{
|
|
|
|
int dno;
|
|
|
|
|
|
|
|
/* initialize ParamListInfo with one entry per datum, all invalid */
|
|
|
|
paramLI = (ParamListInfo)
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
eval_mcontext_alloc0(estate,
|
|
|
|
offsetof(ParamListInfoData, params) +
|
|
|
|
estate->ndatums * sizeof(ParamExternData));
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
paramLI->paramFetch = plpgsql_param_fetch;
|
|
|
|
paramLI->paramFetchArg = (void *) estate;
|
|
|
|
paramLI->parserSetup = (ParserSetupHook) plpgsql_parser_setup;
|
|
|
|
paramLI->parserSetupArg = (void *) expr;
|
|
|
|
paramLI->numParams = estate->ndatums;
|
Fix problems with ParamListInfo serialization mechanism.
Commit d1b7c1ffe72e86932b5395f29e006c3f503bc53d introduced a mechanism
for serializing a ParamListInfo structure to be passed to a parallel
worker. However, this mechanism failed to handle external expanded
values, as pointed out by Noah Misch. Repair.
Moreover, plpgsql_param_fetch requires adjustment because the
serialization mechanism needs it to skip evaluating unused parameters
just as we would do when it is called from copyParamList, but params
== estate->paramLI in that case. To fix, make the bms_is_member test
in that function unconditional.
Finally, have setup_param_list set a new ParamListInfo field,
paramMask, to the parameters actually used in the expression, so that
we don't try to fetch those that are not needed when serializing a
parameter list. This isn't necessary for correctness, but it makes
the performance of the parallel executor code comparable to what we
do for cases involving cursors.
Design suggestions and extensive review by Noah Misch. Patch by me.
2015-11-03 00:11:29 +01:00
|
|
|
paramLI->paramMask = NULL;
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Instantiate values for "safe" parameters of the expression. We
|
|
|
|
* could skip this and leave them to be filled by plpgsql_param_fetch;
|
|
|
|
* but then the values would not be available for query planning,
|
|
|
|
* since the planner doesn't call the paramFetch hook.
|
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
|
|
|
*/
|
2014-11-28 19:37:25 +01:00
|
|
|
dno = -1;
|
|
|
|
while ((dno = bms_next_member(expr->paramnos, dno)) >= 0)
|
2011-09-16 06:42:53 +02:00
|
|
|
{
|
|
|
|
PLpgSQL_datum *datum = estate->datums[dno];
|
|
|
|
|
|
|
|
if (datum->dtype == PLPGSQL_DTYPE_VAR)
|
|
|
|
{
|
|
|
|
PLpgSQL_var *var = (PLpgSQL_var *) datum;
|
|
|
|
ParamExternData *prm = ¶mLI->params[dno];
|
|
|
|
|
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
|
|
|
if (dno == expr->rwparam)
|
|
|
|
prm->value = var->value;
|
|
|
|
else
|
|
|
|
prm->value = MakeExpandedObjectReadOnly(var->value,
|
|
|
|
var->isnull,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
var->datatype->typlen);
|
2011-09-16 06:42:53 +02:00
|
|
|
prm->isnull = var->isnull;
|
|
|
|
prm->pflags = PARAM_FLAG_CONST;
|
|
|
|
prm->ptype = var->datatype->typoid;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-11-04 23:26:08 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Also make sure this is set before parser hooks need it. There is
|
2010-02-26 03:01:40 +01:00
|
|
|
* no need to save and restore, since the value is always correct once
|
2011-09-16 18:31:23 +02:00
|
|
|
* set. (Should be set already, but let's be sure.)
|
2009-11-04 23:26:08 +01:00
|
|
|
*/
|
|
|
|
expr->func = estate->func;
|
2008-04-07 01:43:29 +02:00
|
|
|
}
|
2009-11-04 23:26:08 +01:00
|
|
|
else
|
2011-09-16 18:31:23 +02:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Expression requires no parameters. Be sure we represent this case
|
|
|
|
* as a NULL ParamListInfo, so that plancache.c knows there is no
|
|
|
|
* point in a custom plan.
|
|
|
|
*/
|
2009-11-04 23:26:08 +01:00
|
|
|
paramLI = NULL;
|
2011-09-16 18:31:23 +02:00
|
|
|
}
|
2009-11-04 23:26:08 +01:00
|
|
|
return paramLI;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* plpgsql_param_fetch paramFetch callback for dynamic parameter fetch
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
plpgsql_param_fetch(ParamListInfo params, int paramid)
|
|
|
|
{
|
|
|
|
int dno;
|
|
|
|
PLpgSQL_execstate *estate;
|
|
|
|
PLpgSQL_expr *expr;
|
|
|
|
PLpgSQL_datum *datum;
|
|
|
|
ParamExternData *prm;
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
int32 prmtypmod;
|
2009-11-04 23:26:08 +01:00
|
|
|
|
|
|
|
/* paramid's are 1-based, but dnos are 0-based */
|
|
|
|
dno = paramid - 1;
|
|
|
|
Assert(dno >= 0 && dno < params->numParams);
|
|
|
|
|
|
|
|
/* fetch back the hook data */
|
|
|
|
estate = (PLpgSQL_execstate *) params->paramFetchArg;
|
Allocate ParamListInfo once per plpgsql function, not once per expression.
setup_param_list() was allocating a fresh ParamListInfo for each query or
expression evaluation requested by a plpgsql function. There was probably
once good reason to do it like that, but for a long time we've had a
convention that there's a one-to-one mapping between the function's
PLpgSQL_datum array and the ParamListInfo slots, which means that a single
ParamListInfo can serve all the function's evaluation requests: the data
that would need to be passed is the same anyway.
In this patch, we retain the pattern of zeroing out the ParamListInfo
contents during each setup_param_list() call, because some of the slots may
be stale and we don't know exactly which ones. So this patch only saves a
palloc/pfree per evaluation cycle and nothing more; still, that seems to be
good for a couple percent overall speedup on simple-arithmetic type
statements. In future, though, we might be able to improve matters still
more by managing the param array contents more carefully.
Also, unify the former use of estate->cur_expr with that of
paramLI->parserSetupArg; they both were used to point to the active
expression, so we can combine the variables into just one.
2015-03-11 17:40:43 +01:00
|
|
|
expr = (PLpgSQL_expr *) params->parserSetupArg;
|
2009-11-04 23:26:08 +01:00
|
|
|
Assert(params->numParams == estate->ndatums);
|
|
|
|
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/* now we can access the target datum */
|
|
|
|
datum = estate->datums[dno];
|
|
|
|
|
Fix problems with ParamListInfo serialization mechanism.
Commit d1b7c1ffe72e86932b5395f29e006c3f503bc53d introduced a mechanism
for serializing a ParamListInfo structure to be passed to a parallel
worker. However, this mechanism failed to handle external expanded
values, as pointed out by Noah Misch. Repair.
Moreover, plpgsql_param_fetch requires adjustment because the
serialization mechanism needs it to skip evaluating unused parameters
just as we would do when it is called from copyParamList, but params
== estate->paramLI in that case. To fix, make the bms_is_member test
in that function unconditional.
Finally, have setup_param_list set a new ParamListInfo field,
paramMask, to the parameters actually used in the expression, so that
we don't try to fetch those that are not needed when serializing a
parameter list. This isn't necessary for correctness, but it makes
the performance of the parallel executor code comparable to what we
do for cases involving cursors.
Design suggestions and extensive review by Noah Misch. Patch by me.
2015-11-03 00:11:29 +01:00
|
|
|
/*
|
|
|
|
* Since copyParamList() or SerializeParamList() will try to materialize
|
|
|
|
* every single parameter slot, it's important to do nothing when asked
|
|
|
|
* for a datum that's not supposed to be used by this SQL expression.
|
|
|
|
* Otherwise we risk failures in exec_eval_datum(), or copying a lot more
|
|
|
|
* data than necessary.
|
|
|
|
*/
|
|
|
|
if (!bms_is_member(dno, expr->paramnos))
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (params == estate->paramLI)
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
{
|
|
|
|
/*
|
Fix problems with ParamListInfo serialization mechanism.
Commit d1b7c1ffe72e86932b5395f29e006c3f503bc53d introduced a mechanism
for serializing a ParamListInfo structure to be passed to a parallel
worker. However, this mechanism failed to handle external expanded
values, as pointed out by Noah Misch. Repair.
Moreover, plpgsql_param_fetch requires adjustment because the
serialization mechanism needs it to skip evaluating unused parameters
just as we would do when it is called from copyParamList, but params
== estate->paramLI in that case. To fix, make the bms_is_member test
in that function unconditional.
Finally, have setup_param_list set a new ParamListInfo field,
paramMask, to the parameters actually used in the expression, so that
we don't try to fetch those that are not needed when serializing a
parameter list. This isn't necessary for correctness, but it makes
the performance of the parallel executor code comparable to what we
do for cases involving cursors.
Design suggestions and extensive review by Noah Misch. Patch by me.
2015-11-03 00:11:29 +01:00
|
|
|
* We need to mark the shared params array dirty if we're about to
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* evaluate a resettable datum.
|
|
|
|
*/
|
|
|
|
switch (datum->dtype)
|
|
|
|
{
|
|
|
|
case PLPGSQL_DTYPE_ROW:
|
|
|
|
case PLPGSQL_DTYPE_REC:
|
|
|
|
case PLPGSQL_DTYPE_RECFIELD:
|
|
|
|
estate->params_dirty = true;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-11-04 23:26:08 +01:00
|
|
|
|
|
|
|
/* OK, evaluate the value and store into the appropriate paramlist slot */
|
|
|
|
prm = ¶ms->params[dno];
|
|
|
|
exec_eval_datum(estate, datum,
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
&prm->ptype, &prmtypmod,
|
|
|
|
&prm->value, &prm->isnull);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/* We can always mark params as "const" for executor's purposes */
|
|
|
|
prm->pflags = PARAM_FLAG_CONST;
|
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
|
|
|
|
|
|
|
/*
|
|
|
|
* If it's a read/write expanded datum, convert reference to read-only,
|
|
|
|
* unless it's safe to pass as read-write.
|
|
|
|
*/
|
|
|
|
if (datum->dtype == PLPGSQL_DTYPE_VAR && dno != expr->rwparam)
|
|
|
|
prm->value = MakeExpandedObjectReadOnly(prm->value,
|
|
|
|
prm->isnull,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
((PLpgSQL_var *) datum)->datatype->typlen);
|
2008-04-07 01:43:29 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
2001-04-30 22:05:40 +02:00
|
|
|
* exec_move_row Move one tuple's values into a record or row
|
2012-02-12 00:06:24 +01:00
|
|
|
*
|
|
|
|
* Since this uses exec_assign_value, caller should eventually call
|
|
|
|
* exec_eval_cleanup to prevent long-term memory leaks.
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_move_row(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_rec *rec,
|
|
|
|
PLpgSQL_row *row,
|
1998-09-01 06:40:42 +02:00
|
|
|
HeapTuple tup, TupleDesc tupdesc)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2003-01-21 23:06:12 +01:00
|
|
|
* Record is simple - just copy the tuple and its descriptor into the
|
|
|
|
* record variable
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
if (rec != NULL)
|
|
|
|
{
|
2005-06-20 22:44:44 +02:00
|
|
|
/*
|
2008-09-02 00:30:33 +02:00
|
|
|
* Copy input first, just in case it is pointing at variable's value
|
2005-06-20 22:44:44 +02:00
|
|
|
*/
|
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
tup = heap_copytuple(tup);
|
2008-09-02 00:30:33 +02:00
|
|
|
else if (tupdesc)
|
|
|
|
{
|
|
|
|
/* If we have a tupdesc but no data, form an all-nulls tuple */
|
2008-11-02 02:45:28 +01:00
|
|
|
bool *nulls;
|
2008-09-02 00:30:33 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
nulls = (bool *)
|
|
|
|
eval_mcontext_alloc(estate, tupdesc->natts * sizeof(bool));
|
2008-11-02 02:45:28 +01:00
|
|
|
memset(nulls, true, tupdesc->natts * sizeof(bool));
|
2008-09-02 00:30:33 +02:00
|
|
|
|
2008-11-02 02:45:28 +01:00
|
|
|
tup = heap_form_tuple(tupdesc, NULL, nulls);
|
2008-09-02 00:30:33 +02:00
|
|
|
}
|
|
|
|
|
2005-06-20 22:44:44 +02:00
|
|
|
if (tupdesc)
|
|
|
|
tupdesc = CreateTupleDescCopy(tupdesc);
|
|
|
|
|
2008-09-02 00:30:33 +02:00
|
|
|
/* Free the old value ... */
|
2001-05-21 16:22:19 +02:00
|
|
|
if (rec->freetup)
|
|
|
|
{
|
|
|
|
heap_freetuple(rec->tup);
|
|
|
|
rec->freetup = false;
|
|
|
|
}
|
|
|
|
if (rec->freetupdesc)
|
|
|
|
{
|
|
|
|
FreeTupleDesc(rec->tupdesc);
|
|
|
|
rec->freetupdesc = false;
|
|
|
|
}
|
|
|
|
|
2008-09-02 00:30:33 +02:00
|
|
|
/* ... and install the new */
|
1998-09-01 06:40:42 +02:00
|
|
|
if (HeapTupleIsValid(tup))
|
|
|
|
{
|
2005-06-20 22:44:44 +02:00
|
|
|
rec->tup = tup;
|
2001-05-21 16:22:19 +02:00
|
|
|
rec->freetup = true;
|
2003-01-21 23:06:12 +01:00
|
|
|
}
|
1998-09-01 06:40:42 +02:00
|
|
|
else
|
|
|
|
rec->tup = NULL;
|
2003-01-21 23:06:12 +01:00
|
|
|
|
|
|
|
if (tupdesc)
|
|
|
|
{
|
2005-06-20 22:44:44 +02:00
|
|
|
rec->tupdesc = tupdesc;
|
2003-01-21 23:06:12 +01:00
|
|
|
rec->freetupdesc = true;
|
|
|
|
}
|
|
|
|
else
|
1998-09-01 06:40:42 +02:00
|
|
|
rec->tupdesc = NULL;
|
|
|
|
|
|
|
|
return;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2001-04-30 22:05:40 +02:00
|
|
|
* Row is a bit more complicated in that we assign the individual
|
|
|
|
* attributes of the tuple to the variables the row points to.
|
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* NOTE: this code used to demand row->nfields ==
|
2009-06-11 16:49:15 +02:00
|
|
|
* HeapTupleHeaderGetNatts(tup->t_data), but that's wrong. The tuple
|
|
|
|
* might have more fields than we expected if it's from an
|
|
|
|
* inheritance-child table of the current table, or it might have fewer if
|
|
|
|
* the table has had columns added by ALTER TABLE. Ignore extra columns
|
|
|
|
* and assume NULL for missing columns, the same as heap_getattr would do.
|
|
|
|
* We also have to skip over dropped columns in either the source or
|
|
|
|
* destination.
|
2003-01-21 23:06:12 +01:00
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
* If we have no tuple data at all, we'll assign NULL to all columns of
|
|
|
|
* the row variable.
|
1998-09-01 06:40:42 +02:00
|
|
|
*/
|
|
|
|
if (row != NULL)
|
|
|
|
{
|
2008-09-02 00:30:33 +02:00
|
|
|
int td_natts = tupdesc ? tupdesc->natts : 0;
|
2001-04-30 22:05:40 +02:00
|
|
|
int t_natts;
|
2003-09-26 01:02:12 +02:00
|
|
|
int fnum;
|
|
|
|
int anum;
|
2001-04-30 22:05:40 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
if (HeapTupleIsValid(tup))
|
2007-01-09 23:01:00 +01:00
|
|
|
t_natts = HeapTupleHeaderGetNatts(tup->t_data);
|
2001-04-30 22:05:40 +02:00
|
|
|
else
|
|
|
|
t_natts = 0;
|
|
|
|
|
2003-09-26 01:02:12 +02:00
|
|
|
anum = 0;
|
|
|
|
for (fnum = 0; fnum < row->nfields; fnum++)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2001-04-30 22:05:40 +02:00
|
|
|
PLpgSQL_var *var;
|
|
|
|
Datum value;
|
|
|
|
bool isnull;
|
|
|
|
Oid valtype;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 valtypmod;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
2003-09-26 01:02:12 +02:00
|
|
|
if (row->varnos[fnum] < 0)
|
|
|
|
continue; /* skip dropped column in row struct */
|
|
|
|
|
|
|
|
var = (PLpgSQL_var *) (estate->datums[row->varnos[fnum]]);
|
|
|
|
|
2017-08-20 20:19:07 +02:00
|
|
|
while (anum < td_natts &&
|
|
|
|
TupleDescAttr(tupdesc, anum)->attisdropped)
|
2003-09-26 01:02:12 +02:00
|
|
|
anum++; /* skip dropped column in tuple */
|
|
|
|
|
2008-09-02 00:30:33 +02:00
|
|
|
if (anum < td_natts)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2008-09-02 00:30:33 +02:00
|
|
|
if (anum < t_natts)
|
|
|
|
value = SPI_getbinval(tup, tupdesc, anum + 1, &isnull);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
value = (Datum) 0;
|
|
|
|
isnull = true;
|
|
|
|
}
|
2017-08-20 20:19:07 +02:00
|
|
|
valtype = TupleDescAttr(tupdesc, anum)->atttypid;
|
|
|
|
valtypmod = TupleDescAttr(tupdesc, anum)->atttypmod;
|
2003-09-26 01:02:12 +02:00
|
|
|
anum++;
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
2001-04-30 22:05:40 +02:00
|
|
|
else
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
2001-04-30 22:05:40 +02:00
|
|
|
value = (Datum) 0;
|
|
|
|
isnull = true;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
valtype = UNKNOWNOID;
|
|
|
|
valtypmod = -1;
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
2001-04-30 22:05:40 +02:00
|
|
|
|
2003-09-26 01:02:12 +02:00
|
|
|
exec_assign_value(estate, (PLpgSQL_datum *) var,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
value, isnull, valtype, valtypmod);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2003-07-26 01:37:31 +02:00
|
|
|
elog(ERROR, "unsupported target");
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2003-09-26 01:02:12 +02:00
|
|
|
/* ----------
|
|
|
|
* make_tuple_from_row Make a tuple from the values of a row object
|
|
|
|
*
|
|
|
|
* A NULL return indicates rowtype mismatch; caller must raise suitable error
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
*
|
|
|
|
* The result tuple is freshly palloc'd in caller's context. Some junk
|
|
|
|
* may be left behind in eval_mcontext, too.
|
2003-09-26 01:02:12 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static HeapTuple
|
2005-11-22 19:17:34 +01:00
|
|
|
make_tuple_from_row(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_row *row,
|
2003-09-26 01:02:12 +02:00
|
|
|
TupleDesc tupdesc)
|
|
|
|
{
|
|
|
|
int natts = tupdesc->natts;
|
|
|
|
HeapTuple tuple;
|
|
|
|
Datum *dvalues;
|
2005-09-13 18:16:17 +02:00
|
|
|
bool *nulls;
|
2003-09-26 01:02:12 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (natts != row->nfields)
|
|
|
|
return NULL;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
dvalues = (Datum *) eval_mcontext_alloc0(estate, natts * sizeof(Datum));
|
|
|
|
nulls = (bool *) eval_mcontext_alloc(estate, natts * sizeof(bool));
|
2003-09-26 01:02:12 +02:00
|
|
|
|
|
|
|
for (i = 0; i < natts; i++)
|
|
|
|
{
|
2005-09-13 18:16:17 +02:00
|
|
|
Oid fieldtypeid;
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
int32 fieldtypmod;
|
2003-09-26 01:02:12 +02:00
|
|
|
|
2017-08-20 20:19:07 +02:00
|
|
|
if (TupleDescAttr(tupdesc, i)->attisdropped)
|
2005-09-13 18:16:17 +02:00
|
|
|
{
|
|
|
|
nulls[i] = true; /* leave the column as null */
|
|
|
|
continue;
|
|
|
|
}
|
2003-09-26 01:02:12 +02:00
|
|
|
if (row->varnos[i] < 0) /* should not happen */
|
|
|
|
elog(ERROR, "dropped rowtype entry for non-dropped column");
|
|
|
|
|
2005-09-13 18:16:17 +02:00
|
|
|
exec_eval_datum(estate, estate->datums[row->varnos[i]],
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
&fieldtypeid, &fieldtypmod,
|
|
|
|
&dvalues[i], &nulls[i]);
|
2017-08-20 20:19:07 +02:00
|
|
|
if (fieldtypeid != TupleDescAttr(tupdesc, i)->atttypid)
|
2003-09-26 01:02:12 +02:00
|
|
|
return NULL;
|
Improve handling of domains over arrays.
This patch eliminates various bizarre behaviors caused by sloppy thinking
about the difference between a domain type and its underlying array type.
In particular, the operation of updating one element of such an array
has to be considered as yielding a value of the underlying array type,
*not* a value of the domain, because there's no assurance that the
domain's CHECK constraints are still satisfied. If we're intending to
store the result back into a domain column, we have to re-cast to the
domain type so that constraints are re-checked.
For similar reasons, such a domain can't be blindly matched to an ANYARRAY
polymorphic parameter, because the polymorphic function is likely to apply
array-ish operations that could invalidate the domain constraints. For the
moment, we just forbid such matching. We might later wish to insert an
automatic downcast to the underlying array type, but such a change should
also change matching of domains to ANYELEMENT for consistency.
To ensure that all such logic is rechecked, this patch removes the original
hack of setting a domain's pg_type.typelem field to match its base type;
the typelem will always be zero instead. In those places where it's really
okay to look through the domain type with no other logic changes, use the
newly added get_base_element_type function in place of get_element_type.
catversion bumped due to change in pg_type contents.
Per bug #5717 from Richard Huxton and subsequent discussion.
2010-10-21 22:07:17 +02:00
|
|
|
/* XXX should we insist on typmod match, too? */
|
2003-09-26 01:02:12 +02:00
|
|
|
}
|
|
|
|
|
2005-09-13 18:16:17 +02:00
|
|
|
tuple = heap_form_tuple(tupdesc, dvalues, nulls);
|
2003-09-26 01:02:12 +02:00
|
|
|
|
|
|
|
return tuple;
|
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
2012-12-07 05:09:52 +01:00
|
|
|
/* ----------
|
|
|
|
* get_tuple_from_datum extract a tuple from a composite Datum
|
|
|
|
*
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* Returns a HeapTuple, freshly palloc'd in caller's context.
|
2012-12-07 05:09:52 +01:00
|
|
|
*
|
|
|
|
* Note: it's caller's responsibility to be sure value is of composite type.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static HeapTuple
|
|
|
|
get_tuple_from_datum(Datum value)
|
|
|
|
{
|
|
|
|
HeapTupleHeader td = DatumGetHeapTupleHeader(value);
|
|
|
|
HeapTupleData tmptup;
|
|
|
|
|
|
|
|
/* Build a temporary HeapTuple control structure */
|
|
|
|
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
|
|
|
|
ItemPointerSetInvalid(&(tmptup.t_self));
|
|
|
|
tmptup.t_tableOid = InvalidOid;
|
|
|
|
tmptup.t_data = td;
|
|
|
|
|
|
|
|
/* Build a copy and return it */
|
|
|
|
return heap_copytuple(&tmptup);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* get_tupdesc_from_datum get a tuple descriptor for a composite Datum
|
|
|
|
*
|
|
|
|
* Returns a pointer to the TupleDesc of the tuple's rowtype.
|
|
|
|
* Caller is responsible for calling ReleaseTupleDesc when done with it.
|
|
|
|
*
|
|
|
|
* Note: it's caller's responsibility to be sure value is of composite type.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static TupleDesc
|
|
|
|
get_tupdesc_from_datum(Datum value)
|
|
|
|
{
|
|
|
|
HeapTupleHeader td = DatumGetHeapTupleHeader(value);
|
|
|
|
Oid tupType;
|
|
|
|
int32 tupTypmod;
|
|
|
|
|
|
|
|
/* Extract rowtype info and find a tupdesc */
|
|
|
|
tupType = HeapTupleHeaderGetTypeId(td);
|
|
|
|
tupTypmod = HeapTupleHeaderGetTypMod(td);
|
|
|
|
return lookup_rowtype_tupdesc(tupType, tupTypmod);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_move_row_from_datum Move a composite Datum into a record or row
|
|
|
|
*
|
|
|
|
* This is equivalent to get_tuple_from_datum() followed by exec_move_row(),
|
|
|
|
* but we avoid constructing an intermediate physical copy of the tuple.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
exec_move_row_from_datum(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_rec *rec,
|
|
|
|
PLpgSQL_row *row,
|
|
|
|
Datum value)
|
|
|
|
{
|
|
|
|
HeapTupleHeader td = DatumGetHeapTupleHeader(value);
|
|
|
|
Oid tupType;
|
|
|
|
int32 tupTypmod;
|
|
|
|
TupleDesc tupdesc;
|
|
|
|
HeapTupleData tmptup;
|
|
|
|
|
|
|
|
/* Extract rowtype info and find a tupdesc */
|
|
|
|
tupType = HeapTupleHeaderGetTypeId(td);
|
|
|
|
tupTypmod = HeapTupleHeaderGetTypMod(td);
|
|
|
|
tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod);
|
|
|
|
|
|
|
|
/* Build a temporary HeapTuple control structure */
|
|
|
|
tmptup.t_len = HeapTupleHeaderGetDatumLength(td);
|
|
|
|
ItemPointerSetInvalid(&(tmptup.t_self));
|
|
|
|
tmptup.t_tableOid = InvalidOid;
|
|
|
|
tmptup.t_data = td;
|
|
|
|
|
|
|
|
/* Do the move */
|
|
|
|
exec_move_row(estate, rec, row, &tmptup, tupdesc);
|
|
|
|
|
|
|
|
/* Release tupdesc usage count */
|
|
|
|
ReleaseTupleDesc(tupdesc);
|
|
|
|
}
|
|
|
|
|
2003-10-01 23:47:42 +02:00
|
|
|
/* ----------
|
|
|
|
* convert_value_to_string Convert a non-null Datum to C string
|
|
|
|
*
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* Note: the result is in the estate's eval_mcontext, and will be cleared
|
2012-02-12 00:06:24 +01:00
|
|
|
* by the next exec_eval_cleanup() call. The invoked output function might
|
|
|
|
* leave additional cruft there as well, so just pfree'ing the result string
|
|
|
|
* would not be enough to avoid memory leaks if we did not do it like this.
|
|
|
|
* In most usages the Datum being passed in is also in that context (if
|
|
|
|
* pass-by-reference) and so an exec_eval_cleanup() call is needed anyway.
|
2006-04-04 21:35:37 +02:00
|
|
|
*
|
|
|
|
* Note: not caching the conversion function lookup is bad for performance.
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
* However, this function isn't currently used in any places where an extra
|
|
|
|
* catalog lookup or two seems like a big deal.
|
2003-10-01 23:47:42 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static char *
|
2012-02-12 00:06:24 +01:00
|
|
|
convert_value_to_string(PLpgSQL_execstate *estate, Datum value, Oid valtype)
|
2003-10-01 23:47:42 +02:00
|
|
|
{
|
2012-02-12 00:06:24 +01:00
|
|
|
char *result;
|
|
|
|
MemoryContext oldcontext;
|
2004-06-06 02:41:28 +02:00
|
|
|
Oid typoutput;
|
2003-10-01 23:47:42 +02:00
|
|
|
bool typIsVarlena;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
2005-05-01 20:56:19 +02:00
|
|
|
getTypeOutputInfo(valtype, &typoutput, &typIsVarlena);
|
2012-02-12 00:06:24 +01:00
|
|
|
result = OidOutputFunctionCall(typoutput, value);
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
return result;
|
2003-10-01 23:47:42 +02:00
|
|
|
}
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
|
|
|
* exec_cast_value Cast a value if required
|
2012-02-12 00:06:24 +01:00
|
|
|
*
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
* Note that *isnull is an input and also an output parameter. While it's
|
|
|
|
* unlikely that a cast operation would produce null from non-null or vice
|
|
|
|
* versa, that could happen in principle.
|
|
|
|
*
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* Note: the estate's eval_mcontext is used for temporary storage, and may
|
2012-02-12 00:06:24 +01:00
|
|
|
* also contain the result Datum if we have to do a conversion to a pass-
|
2014-05-06 18:12:18 +02:00
|
|
|
* by-reference data type. Be sure to do an exec_eval_cleanup() call when
|
2012-02-12 00:06:24 +01:00
|
|
|
* done with the result.
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static Datum
|
2012-02-12 00:06:24 +01:00
|
|
|
exec_cast_value(PLpgSQL_execstate *estate,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
Datum value, bool *isnull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
Oid valtype, int32 valtypmod,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
Oid reqtype, int32 reqtypmod)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
2006-04-04 21:35:37 +02:00
|
|
|
/*
|
2012-02-12 00:06:24 +01:00
|
|
|
* If the type of the given value isn't what's requested, convert it.
|
2006-04-04 21:35:37 +02:00
|
|
|
*/
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
if (valtype != reqtype ||
|
|
|
|
(valtypmod != reqtypmod && reqtypmod != -1))
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
plpgsql_CastHashEntry *cast_entry;
|
2012-02-12 00:06:24 +01:00
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
cast_entry = get_cast_hashentry(estate,
|
2015-03-05 02:23:13 +01:00
|
|
|
valtype, valtypmod,
|
|
|
|
reqtype, reqtypmod);
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
if (cast_entry)
|
1998-09-01 06:40:42 +02:00
|
|
|
{
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
ExprContext *econtext = estate->eval_econtext;
|
|
|
|
MemoryContext oldcontext;
|
1998-09-01 06:40:42 +02:00
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
|
|
|
econtext->caseValue_datum = value;
|
|
|
|
econtext->caseValue_isNull = *isnull;
|
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
cast_entry->cast_in_use = true;
|
|
|
|
|
|
|
|
value = ExecEvalExpr(cast_entry->cast_exprstate, econtext,
|
2017-01-19 23:12:38 +01:00
|
|
|
isnull);
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
|
|
|
|
cast_entry->cast_in_use = false;
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2006-04-04 21:35:37 +02:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
return value;
|
1998-08-22 14:38:39 +02:00
|
|
|
}
|
|
|
|
|
2003-03-25 04:16:41 +01:00
|
|
|
/* ----------
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
* get_cast_hashentry Look up how to perform a type cast
|
2003-03-25 04:16:41 +01:00
|
|
|
*
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
* Returns a plpgsql_CastHashEntry if an expression has to be evaluated,
|
|
|
|
* or NULL if the cast is a mere no-op relabeling. If there's work to be
|
|
|
|
* done, the cast_exprstate field contains an expression evaluation tree
|
|
|
|
* based on a CaseTestExpr input, and the cast_in_use field should be set
|
|
|
|
* TRUE while executing it.
|
2003-03-25 04:16:41 +01:00
|
|
|
* ----------
|
|
|
|
*/
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
static plpgsql_CastHashEntry *
|
|
|
|
get_cast_hashentry(PLpgSQL_execstate *estate,
|
|
|
|
Oid srctype, int32 srctypmod,
|
|
|
|
Oid dsttype, int32 dsttypmod)
|
2003-03-25 04:16:41 +01:00
|
|
|
{
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
plpgsql_CastHashKey cast_key;
|
|
|
|
plpgsql_CastHashEntry *cast_entry;
|
|
|
|
bool found;
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
LocalTransactionId curlxid;
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
|
|
|
/* Look for existing entry */
|
|
|
|
cast_key.srctype = srctype;
|
|
|
|
cast_key.dsttype = dsttype;
|
2015-03-05 02:23:13 +01:00
|
|
|
cast_key.srctypmod = srctypmod;
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
cast_key.dsttypmod = dsttypmod;
|
2015-08-15 18:00:36 +02:00
|
|
|
cast_entry = (plpgsql_CastHashEntry *) hash_search(estate->cast_hash,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
(void *) &cast_key,
|
|
|
|
HASH_FIND, NULL);
|
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
if (cast_entry == NULL)
|
|
|
|
{
|
|
|
|
/* We've not looked up this coercion before */
|
|
|
|
Node *cast_expr;
|
|
|
|
CaseTestExpr *placeholder;
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
/*
|
|
|
|
* Since we could easily fail (no such coercion), construct a
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* temporary coercion expression tree in the short-lived
|
|
|
|
* eval_mcontext, then if successful copy it to cast_hash_context.
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
*/
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
/*
|
|
|
|
* We use a CaseTestExpr as the base of the coercion tree, since it's
|
|
|
|
* very cheap to insert the source value for that.
|
|
|
|
*/
|
|
|
|
placeholder = makeNode(CaseTestExpr);
|
|
|
|
placeholder->typeId = srctype;
|
|
|
|
placeholder->typeMod = srctypmod;
|
|
|
|
placeholder->collation = get_typcollation(srctype);
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
/*
|
|
|
|
* Apply coercion. We use ASSIGNMENT coercion because that's the
|
|
|
|
* closest match to plpgsql's historical behavior; in particular,
|
|
|
|
* EXPLICIT coercion would allow silent truncation to a destination
|
|
|
|
* varchar/bpchar's length, which we do not want.
|
|
|
|
*
|
|
|
|
* If source type is UNKNOWN, coerce_to_target_type will fail (it only
|
|
|
|
* expects to see that for Const input nodes), so don't call it; we'll
|
|
|
|
* apply CoerceViaIO instead. Likewise, it doesn't currently work for
|
|
|
|
* coercing RECORD to some other type, so skip for that too.
|
|
|
|
*/
|
|
|
|
if (srctype == UNKNOWNOID || srctype == RECORDOID)
|
|
|
|
cast_expr = NULL;
|
|
|
|
else
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
cast_expr = coerce_to_target_type(NULL,
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
(Node *) placeholder, srctype,
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
dsttype, dsttypmod,
|
|
|
|
COERCION_ASSIGNMENT,
|
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
-1);
|
2003-03-25 04:16:41 +01:00
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
/*
|
|
|
|
* If there's no cast path according to the parser, fall back to using
|
|
|
|
* an I/O coercion; this is semantically dubious but matches plpgsql's
|
|
|
|
* historical behavior. We would need something of the sort for
|
|
|
|
* UNKNOWN literals in any case.
|
|
|
|
*/
|
|
|
|
if (cast_expr == NULL)
|
|
|
|
{
|
|
|
|
CoerceViaIO *iocoerce = makeNode(CoerceViaIO);
|
|
|
|
|
|
|
|
iocoerce->arg = (Expr *) placeholder;
|
|
|
|
iocoerce->resulttype = dsttype;
|
|
|
|
iocoerce->resultcollid = InvalidOid;
|
|
|
|
iocoerce->coerceformat = COERCE_IMPLICIT_CAST;
|
|
|
|
iocoerce->location = -1;
|
|
|
|
cast_expr = (Node *) iocoerce;
|
|
|
|
if (dsttypmod != -1)
|
|
|
|
cast_expr = coerce_to_target_type(NULL,
|
|
|
|
cast_expr, dsttype,
|
|
|
|
dsttype, dsttypmod,
|
|
|
|
COERCION_ASSIGNMENT,
|
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Note: we don't bother labeling the expression tree with collation */
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
/* Detect whether we have a no-op (RelabelType) coercion */
|
|
|
|
if (IsA(cast_expr, RelabelType) &&
|
|
|
|
((RelabelType *) cast_expr)->arg == (Expr *) placeholder)
|
|
|
|
cast_expr = NULL;
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
if (cast_expr)
|
|
|
|
{
|
|
|
|
/* ExecInitExpr assumes we've planned the expression */
|
|
|
|
cast_expr = (Node *) expression_planner((Expr *) cast_expr);
|
|
|
|
|
|
|
|
/* Now copy the tree into cast_hash_context */
|
2015-08-15 18:00:36 +02:00
|
|
|
MemoryContextSwitchTo(estate->cast_hash_context);
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
|
|
|
|
cast_expr = copyObject(cast_expr);
|
|
|
|
}
|
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
|
|
|
/* Now we can fill in a hashtable entry. */
|
2015-08-15 18:00:36 +02:00
|
|
|
cast_entry = (plpgsql_CastHashEntry *) hash_search(estate->cast_hash,
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
(void *) &cast_key,
|
Phase 3 of pgindent updates.
Don't move parenthesized lines to the left, even if that means they
flow past the right margin.
By default, BSD indent lines up statement continuation lines that are
within parentheses so that they start just to the right of the preceding
left parenthesis. However, traditionally, if that resulted in the
continuation line extending to the right of the desired right margin,
then indent would push it left just far enough to not overrun the margin,
if it could do so without making the continuation line start to the left of
the current statement indent. That makes for a weird mix of indentations
unless one has been completely rigid about never violating the 80-column
limit.
This behavior has been pretty universally panned by Postgres developers.
Hence, disable it with indent's new -lpl switch, so that parenthesized
lines are always lined up with the preceding left paren.
This patch is much less interesting than the first round of indent
changes, but also bulkier, so I thought it best to separate the effects.
Discussion: https://postgr.es/m/E1dAmxK-0006EE-1r@gemulon.postgresql.org
Discussion: https://postgr.es/m/30527.1495162840@sss.pgh.pa.us
2017-06-21 21:35:54 +02:00
|
|
|
HASH_ENTER, &found);
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
Assert(!found); /* wasn't there a moment ago */
|
|
|
|
cast_entry->cast_expr = (Expr *) cast_expr;
|
|
|
|
cast_entry->cast_exprstate = NULL;
|
|
|
|
cast_entry->cast_in_use = false;
|
|
|
|
cast_entry->cast_lxid = InvalidLocalTransactionId;
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
}
|
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
/* Done if we have determined that this is a no-op cast. */
|
|
|
|
if (cast_entry->cast_expr == NULL)
|
|
|
|
return NULL;
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
|
|
|
/*
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
* Prepare the expression for execution, if it's not been done already in
|
|
|
|
* the current transaction; also, if it's marked busy in the current
|
|
|
|
* transaction, abandon that expression tree and build a new one, so as to
|
|
|
|
* avoid potential problems with recursive cast expressions and failed
|
|
|
|
* executions. (We will leak some memory intra-transaction if that
|
|
|
|
* happens a lot, but we don't expect it to.) It's okay to update the
|
|
|
|
* hash table with the new tree because all plpgsql functions within a
|
2015-08-15 18:00:36 +02:00
|
|
|
* given transaction share the same simple_eval_estate. (Well, regular
|
|
|
|
* functions do; DO blocks have private simple_eval_estates, and private
|
|
|
|
* cast hash tables to go with them.)
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
*/
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
curlxid = MyProc->lxid;
|
|
|
|
if (cast_entry->cast_lxid != curlxid || cast_entry->cast_in_use)
|
|
|
|
{
|
|
|
|
oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
|
|
|
|
cast_entry->cast_exprstate = ExecInitExpr(cast_entry->cast_expr, NULL);
|
|
|
|
cast_entry->cast_in_use = false;
|
|
|
|
cast_entry->cast_lxid = curlxid;
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
}
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
|
Repair mishandling of cached cast-expression trees in plpgsql.
In commit 1345cc67bbb014209714af32b5681b1e11eaf964, I introduced caching
of expressions representing type-cast operations into plpgsql. However,
I supposed that I could cache both the expression trees and the evaluation
state trees derived from them for the life of the session. This doesn't
work, because we execute the expressions in plpgsql's simple_eval_estate,
which has an ecxt_per_query_memory that is only transaction-lifespan.
Therefore we can end up putting pointers into the evaluation state tree
that point to transaction-lifespan memory; in particular this happens if
the cast expression calls a SQL-language function, as reported by Geoff
Winkless.
The minimum-risk fix seems to be to treat the state trees the same way
we do for "simple expression" trees in plpgsql, ie create them in the
simple_eval_estate's ecxt_per_query_memory, which means recreating them
once per transaction.
Since I had to introduce bookkeeping overhead for that anyway, I bought
back some of the added cost by sharing the read-only expression trees
across all functions in the session, instead of using a per-function
table as originally. The simple-expression bookkeeping takes care of
the recursive-usage risk that I was concerned about avoiding before.
At some point we should take a harder look at how all this works,
and see if we can't reduce the amount of tree reinitialization needed.
But that won't happen for 9.5.
2015-07-17 21:53:09 +02:00
|
|
|
return cast_entry;
|
Use standard casting mechanism to convert types in plpgsql, when possible.
plpgsql's historical method for converting datatypes during assignments was
to apply the source type's output function and then the destination type's
input function. Aside from being miserably inefficient in most cases, this
method failed outright in many cases where a user might expect it to work;
an example is that "declare x int; ... x := 3.9;" would fail, not round the
value to 4.
Instead, let's convert by applying the appropriate assignment cast whenever
there is one. To avoid breaking compatibility unnecessarily, fall back to
the I/O conversion method if there is no assignment cast.
So far as I can tell, there is just one case where this method produces a
different result than the old code in a case where the old code would not
have thrown an error. That is assignment of a boolean value to a string
variable (type text, varchar, or bpchar); the old way gave boolean's output
representation, ie 't'/'f', while the new way follows the behavior of the
bool-to-text cast and so gives 'true' or 'false'. This will need to be
called out as an incompatibility in the 9.5 release notes.
Aside from handling many conversion cases more sanely, this method is
often significantly faster than the old way. In part that's because
of more effective caching of the conversion info.
2015-03-04 17:04:30 +01:00
|
|
|
}
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1999-01-27 17:15:22 +01:00
|
|
|
|
|
|
|
/* ----------
|
|
|
|
* exec_simple_check_plan - Check if a plan is simple enough to
|
|
|
|
* be evaluated by ExecEvalExpr() instead
|
|
|
|
* of SPI.
|
|
|
|
* ----------
|
|
|
|
*/
|
|
|
|
static void
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
exec_simple_check_plan(PLpgSQL_execstate *estate, PLpgSQL_expr *expr)
|
1999-01-27 17:15:22 +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
|
|
|
List *plansources;
|
2007-03-16 00:12:07 +01:00
|
|
|
CachedPlanSource *plansource;
|
2011-09-16 06:42:53 +02:00
|
|
|
Query *query;
|
|
|
|
CachedPlan *cplan;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
1999-01-27 17:15:22 +01:00
|
|
|
|
2007-03-16 00:12:07 +01:00
|
|
|
/*
|
2017-08-15 18:28:39 +02:00
|
|
|
* Initialize to "not simple".
|
2007-03-16 00:12:07 +01:00
|
|
|
*/
|
2003-09-29 01:37:45 +02:00
|
|
|
expr->expr_simple_expr = NULL;
|
2017-08-15 18:28:39 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check the analyzed-and-rewritten form of the query to see if we will be
|
|
|
|
* able to treat it as a simple expression. Since this function is only
|
|
|
|
* called immediately after creating the CachedPlanSource, we need not
|
|
|
|
* worry about the query being stale.
|
|
|
|
*/
|
1999-01-27 17:15:22 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2011-09-16 06:42:53 +02:00
|
|
|
* We can only test queries that resulted in exactly one CachedPlanSource
|
1999-01-27 17:15:22 +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
|
|
|
plansources = SPI_plan_get_plan_sources(expr->plan);
|
|
|
|
if (list_length(plansources) != 1)
|
2007-02-20 18:32:18 +01:00
|
|
|
return;
|
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
|
|
|
plansource = (CachedPlanSource *) linitial(plansources);
|
2011-09-16 06:42:53 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* 1. There must be one single querytree.
|
|
|
|
*/
|
|
|
|
if (list_length(plansource->query_list) != 1)
|
1999-01-27 17:15:22 +01:00
|
|
|
return;
|
2011-09-16 06:42:53 +02:00
|
|
|
query = (Query *) linitial(plansource->query_list);
|
1999-01-27 17:15:22 +01:00
|
|
|
|
2011-09-16 06:42:53 +02:00
|
|
|
/*
|
|
|
|
* 2. It must be a plain SELECT query without any input tables
|
|
|
|
*/
|
|
|
|
if (!IsA(query, Query))
|
|
|
|
return;
|
Restructure SELECT INTO's parsetree representation into CreateTableAsStmt.
Making this operation look like a utility statement seems generally a good
idea, and particularly so in light of the desire to provide command
triggers for utility statements. The original choice of representing it as
SELECT with an IntoClause appendage had metastasized into rather a lot of
places, unfortunately, so that this patch is a great deal more complicated
than one might at first expect.
In particular, keeping EXPLAIN working for SELECT INTO and CREATE TABLE AS
subcommands required restructuring some EXPLAIN-related APIs. Add-on code
that calls ExplainOnePlan or ExplainOneUtility, or uses
ExplainOneQuery_hook, will need adjustment.
Also, the cases PREPARE ... SELECT INTO and CREATE RULE ... SELECT INTO,
which formerly were accepted though undocumented, are no longer accepted.
The PREPARE case can be replaced with use of CREATE TABLE AS EXECUTE.
The CREATE RULE case doesn't seem to have much real-world use (since the
rule would work only once before failing with "table already exists"),
so we'll not bother with that one.
Both SELECT INTO and CREATE TABLE AS still return a command tag of
"SELECT nnnn". There was some discussion of returning "CREATE TABLE nnnn",
but for the moment backwards compatibility wins the day.
Andres Freund and Tom Lane
2012-03-20 02:37:19 +01:00
|
|
|
if (query->commandType != CMD_SELECT)
|
2011-09-16 06:42:53 +02:00
|
|
|
return;
|
|
|
|
if (query->rtable != NIL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
2017-08-15 18:28:39 +02:00
|
|
|
* 3. Can't have any subplans, aggregates, qual clauses either. (These
|
|
|
|
* tests should generally match what inline_function() checks before
|
|
|
|
* inlining a SQL function; otherwise, inlining could change our
|
|
|
|
* conclusion about whether an expression is simple, which we don't want.)
|
2011-09-16 06:42:53 +02:00
|
|
|
*/
|
|
|
|
if (query->hasAggs ||
|
|
|
|
query->hasWindowFuncs ||
|
2016-09-13 19:54:24 +02:00
|
|
|
query->hasTargetSRFs ||
|
2011-09-16 06:42:53 +02:00
|
|
|
query->hasSubLinks ||
|
|
|
|
query->cteList ||
|
2017-08-15 18:28:39 +02:00
|
|
|
query->jointree->fromlist ||
|
2011-09-16 06:42:53 +02:00
|
|
|
query->jointree->quals ||
|
|
|
|
query->groupClause ||
|
2017-08-15 18:28:39 +02:00
|
|
|
query->groupingSets ||
|
2011-09-16 06:42:53 +02:00
|
|
|
query->havingQual ||
|
|
|
|
query->windowClause ||
|
|
|
|
query->distinctClause ||
|
|
|
|
query->sortClause ||
|
|
|
|
query->limitOffset ||
|
|
|
|
query->limitCount ||
|
|
|
|
query->setOperations)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 4. The query must have a single attribute as result
|
|
|
|
*/
|
|
|
|
if (list_length(query->targetList) != 1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
2017-08-15 18:28:39 +02:00
|
|
|
* OK, we can treat it as a simple plan.
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
*
|
|
|
|
* Get the generic plan for the query. If replanning is needed, do that
|
|
|
|
* work in the eval_mcontext.
|
2011-09-16 06:42:53 +02:00
|
|
|
*/
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
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
|
|
|
cplan = SPI_plan_get_cached_plan(expr->plan);
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
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
|
|
|
|
|
|
|
/* Can't fail, because we checked for a single CachedPlanSource above */
|
|
|
|
Assert(cplan != NULL);
|
2011-09-16 06:42:53 +02:00
|
|
|
|
2017-08-15 18:28:39 +02:00
|
|
|
/* Share the remaining work with replan code path */
|
|
|
|
exec_save_simple_expr(expr, cplan);
|
2011-09-16 06:42:53 +02:00
|
|
|
|
|
|
|
/* Release our plan refcount */
|
|
|
|
ReleaseCachedPlan(cplan, true);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2017-08-15 18:28:39 +02:00
|
|
|
* exec_save_simple_expr --- extract simple expression from CachedPlan
|
2011-09-16 06:42:53 +02:00
|
|
|
*/
|
|
|
|
static void
|
2017-08-15 18:28:39 +02:00
|
|
|
exec_save_simple_expr(PLpgSQL_expr *expr, CachedPlan *cplan)
|
2011-09-16 06:42:53 +02:00
|
|
|
{
|
|
|
|
PlannedStmt *stmt;
|
|
|
|
Plan *plan;
|
2017-08-15 22:49:47 +02:00
|
|
|
Expr *tle_expr;
|
2011-09-16 06:42:53 +02:00
|
|
|
|
|
|
|
/*
|
2017-08-15 18:28:39 +02:00
|
|
|
* Given the checks that exec_simple_check_plan did, none of the Asserts
|
|
|
|
* here should ever fail.
|
2011-09-16 06:42:53 +02:00
|
|
|
*/
|
|
|
|
|
2017-08-15 18:28:39 +02:00
|
|
|
/* Extract the single PlannedStmt */
|
|
|
|
Assert(list_length(cplan->stmt_list) == 1);
|
Improve castNode notation by introducing list-extraction-specific variants.
This extends the castNode() notation introduced by commit 5bcab1114 to
provide, in one step, extraction of a list cell's pointer and coercion to
a concrete node type. For example, "lfirst_node(Foo, lc)" is the same
as "castNode(Foo, lfirst(lc))". Almost half of the uses of castNode
that have appeared so far include a list extraction call, so this is
pretty widely useful, and it saves a few more keystrokes compared to the
old way.
As with the previous patch, back-patch the addition of these macros to
pg_list.h, so that the notation will be available when back-patching.
Patch by me, after an idea of Andrew Gierth's.
Discussion: https://postgr.es/m/14197.1491841216@sss.pgh.pa.us
2017-04-10 19:51:29 +02:00
|
|
|
stmt = linitial_node(PlannedStmt, cplan->stmt_list);
|
2017-08-15 18:28:39 +02:00
|
|
|
Assert(stmt->commandType == CMD_SELECT);
|
2017-08-15 22:49:47 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Ordinarily, the plan node should be a simple Result. However, if
|
|
|
|
* force_parallel_mode is on, the planner might've stuck a Gather node
|
|
|
|
* atop that. The simplest way to deal with this is to look through the
|
|
|
|
* Gather node. The Gather node's tlist would normally contain a Var
|
|
|
|
* referencing the child node's output ... but setrefs.c might also have
|
|
|
|
* copied a Const as-is.
|
|
|
|
*/
|
2007-02-20 18:32:18 +01:00
|
|
|
plan = stmt->planTree;
|
2017-08-15 22:49:47 +02:00
|
|
|
for (;;)
|
|
|
|
{
|
|
|
|
/* Extract the single tlist expression */
|
|
|
|
Assert(list_length(plan->targetlist) == 1);
|
|
|
|
tle_expr = castNode(TargetEntry, linitial(plan->targetlist))->expr;
|
2017-08-15 18:28:39 +02:00
|
|
|
|
2017-08-15 22:49:47 +02:00
|
|
|
if (IsA(plan, Result))
|
|
|
|
{
|
|
|
|
Assert(plan->lefttree == NULL &&
|
|
|
|
plan->righttree == NULL &&
|
|
|
|
plan->initPlan == NULL &&
|
|
|
|
plan->qual == NULL &&
|
|
|
|
((Result *) plan)->resconstantqual == NULL);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (IsA(plan, Gather))
|
|
|
|
{
|
|
|
|
Assert(plan->lefttree != NULL &&
|
|
|
|
plan->righttree == NULL &&
|
|
|
|
plan->initPlan == NULL &&
|
|
|
|
plan->qual == NULL);
|
|
|
|
/* If setrefs.c copied up a Const, no need to look further */
|
|
|
|
if (IsA(tle_expr, Const))
|
|
|
|
break;
|
|
|
|
/* Otherwise, it better be an outer Var */
|
|
|
|
Assert(IsA(tle_expr, Var));
|
|
|
|
Assert(((Var *) tle_expr)->varno == OUTER_VAR);
|
|
|
|
/* Descend to the child node */
|
|
|
|
plan = plan->lefttree;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
elog(ERROR, "unexpected plan node type: %d",
|
|
|
|
(int) nodeTag(plan));
|
|
|
|
}
|
2000-03-11 07:19:00 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2017-08-15 18:28:39 +02:00
|
|
|
* Save the simple expression, and initialize state to "not valid in
|
|
|
|
* current transaction".
|
1999-01-27 17:15:22 +01:00
|
|
|
*/
|
2017-08-15 22:49:47 +02:00
|
|
|
expr->expr_simple_expr = tle_expr;
|
2017-08-15 18:28:39 +02:00
|
|
|
expr->expr_simple_generation = cplan->generation;
|
2003-09-29 01:37:45 +02:00
|
|
|
expr->expr_simple_state = NULL;
|
2010-10-28 19:00:54 +02:00
|
|
|
expr->expr_simple_in_use = false;
|
2009-04-09 04:57:53 +02:00
|
|
|
expr->expr_simple_lxid = InvalidLocalTransactionId;
|
2002-12-15 17:17:59 +01:00
|
|
|
/* Also stash away the expression result type */
|
2017-08-15 22:49:47 +02:00
|
|
|
expr->expr_simple_type = exprType((Node *) tle_expr);
|
|
|
|
expr->expr_simple_typmod = exprTypmod((Node *) tle_expr);
|
1999-01-27 17:15:22 +01:00
|
|
|
}
|
|
|
|
|
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
|
|
|
/*
|
|
|
|
* exec_check_rw_parameter --- can we pass expanded object as read/write param?
|
|
|
|
*
|
|
|
|
* If we have an assignment like "x := array_append(x, foo)" in which the
|
|
|
|
* top-level function is trusted not to corrupt its argument in case of an
|
|
|
|
* error, then when x has an expanded object as value, it is safe to pass the
|
|
|
|
* value as a read/write pointer and let the function modify the value
|
|
|
|
* in-place.
|
|
|
|
*
|
|
|
|
* This function checks for a safe expression, and sets expr->rwparam to the
|
|
|
|
* dno of the target variable (x) if safe, or -1 if not safe.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
exec_check_rw_parameter(PLpgSQL_expr *expr, int target_dno)
|
|
|
|
{
|
|
|
|
Oid funcid;
|
|
|
|
List *fargs;
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
/* Assume unsafe */
|
|
|
|
expr->rwparam = -1;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the expression isn't simple, there's no point in trying to optimize
|
|
|
|
* (because the exec_run_select code path will flatten any expanded result
|
|
|
|
* anyway). Even without that, this seems like a good safety restriction.
|
|
|
|
*/
|
|
|
|
if (expr->expr_simple_expr == NULL)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If target variable isn't referenced by expression, no need to look
|
|
|
|
* further.
|
|
|
|
*/
|
|
|
|
if (!bms_is_member(target_dno, expr->paramnos))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Top level of expression must be a simple FuncExpr or OpExpr.
|
|
|
|
*/
|
|
|
|
if (IsA(expr->expr_simple_expr, FuncExpr))
|
|
|
|
{
|
|
|
|
FuncExpr *fexpr = (FuncExpr *) expr->expr_simple_expr;
|
|
|
|
|
|
|
|
funcid = fexpr->funcid;
|
|
|
|
fargs = fexpr->args;
|
|
|
|
}
|
|
|
|
else if (IsA(expr->expr_simple_expr, OpExpr))
|
|
|
|
{
|
|
|
|
OpExpr *opexpr = (OpExpr *) expr->expr_simple_expr;
|
|
|
|
|
|
|
|
funcid = opexpr->opfuncid;
|
|
|
|
fargs = opexpr->args;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The top-level function must be one that we trust to be "safe".
|
|
|
|
* Currently we hard-wire the list, but it would be very desirable to
|
|
|
|
* allow extensions to mark their functions as safe ...
|
|
|
|
*/
|
|
|
|
if (!(funcid == F_ARRAY_APPEND ||
|
|
|
|
funcid == F_ARRAY_PREPEND))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* The target variable (in the form of a Param) must only appear as a
|
|
|
|
* direct argument of the top-level function.
|
|
|
|
*/
|
|
|
|
foreach(lc, fargs)
|
|
|
|
{
|
|
|
|
Node *arg = (Node *) lfirst(lc);
|
|
|
|
|
|
|
|
/* A Param is OK, whether it's the target variable or not */
|
|
|
|
if (arg && IsA(arg, Param))
|
|
|
|
continue;
|
|
|
|
/* Otherwise, argument expression must not reference target */
|
|
|
|
if (contains_target_param(arg, &target_dno))
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* OK, we can pass target as a read-write parameter */
|
|
|
|
expr->rwparam = target_dno;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Recursively check for a Param referencing the target variable
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
contains_target_param(Node *node, int *target_dno)
|
|
|
|
{
|
|
|
|
if (node == NULL)
|
|
|
|
return false;
|
|
|
|
if (IsA(node, Param))
|
|
|
|
{
|
|
|
|
Param *param = (Param *) node;
|
|
|
|
|
|
|
|
if (param->paramkind == PARAM_EXTERN &&
|
|
|
|
param->paramid == *target_dno + 1)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return expression_tree_walker(node, contains_target_param,
|
|
|
|
(void *) target_dno);
|
|
|
|
}
|
|
|
|
|
1998-08-22 14:38:39 +02:00
|
|
|
/* ----------
|
2011-11-27 18:57:11 +01:00
|
|
|
* exec_set_found Set the global found variable to true/false
|
1998-08-22 14:38:39 +02:00
|
|
|
* ----------
|
|
|
|
*/
|
1998-09-01 06:40:42 +02:00
|
|
|
static void
|
2005-11-22 19:17:34 +01:00
|
|
|
exec_set_found(PLpgSQL_execstate *estate, bool state)
|
1998-08-22 14:38:39 +02:00
|
|
|
{
|
1998-09-01 06:40:42 +02:00
|
|
|
PLpgSQL_var *var;
|
1998-08-22 14:38:39 +02:00
|
|
|
|
1998-09-01 06:40:42 +02:00
|
|
|
var = (PLpgSQL_var *) (estate->datums[estate->found_varno]);
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(estate, var, BoolGetDatum(state), false, false);
|
1998-09-01 06:40:42 +02:00
|
|
|
}
|
2003-09-29 01:37:45 +02:00
|
|
|
|
2007-01-28 17:15:49 +01:00
|
|
|
/*
|
|
|
|
* plpgsql_create_econtext --- create an eval_econtext for the current function
|
|
|
|
*
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
* We may need to create a new shared_simple_eval_estate too, if there's not
|
|
|
|
* one already for the current transaction. The EState will be cleaned up at
|
2009-04-09 04:57:53 +02:00
|
|
|
* transaction end.
|
2007-01-28 17:15:49 +01:00
|
|
|
*/
|
|
|
|
static void
|
|
|
|
plpgsql_create_econtext(PLpgSQL_execstate *estate)
|
|
|
|
{
|
2009-04-09 04:57:53 +02:00
|
|
|
SimpleEcontextStackEntry *entry;
|
2007-01-28 17:15:49 +01:00
|
|
|
|
2009-04-09 04:57:53 +02:00
|
|
|
/*
|
|
|
|
* Create an EState for evaluation of simple expressions, if there's not
|
2014-05-06 18:12:18 +02:00
|
|
|
* one already in the current transaction. The EState is made a child of
|
2009-04-09 04:57:53 +02:00
|
|
|
* TopTransactionContext so it will have the right lifespan.
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
*
|
|
|
|
* Note that this path is never taken when executing a DO block; the
|
|
|
|
* required EState was already made by plpgsql_inline_handler.
|
2009-04-09 04:57:53 +02:00
|
|
|
*/
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
if (estate->simple_eval_estate == NULL)
|
2007-01-28 17:15:49 +01:00
|
|
|
{
|
|
|
|
MemoryContext oldcontext;
|
|
|
|
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
Assert(shared_simple_eval_estate == NULL);
|
2009-04-09 04:57:53 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(TopTransactionContext);
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
shared_simple_eval_estate = CreateExecutorState();
|
|
|
|
estate->simple_eval_estate = shared_simple_eval_estate;
|
2007-01-28 17:15:49 +01:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2009-04-09 04:57:53 +02:00
|
|
|
}
|
2007-01-28 17:15:49 +01:00
|
|
|
|
2009-04-09 04:57:53 +02:00
|
|
|
/*
|
|
|
|
* Create a child econtext for the current function.
|
|
|
|
*/
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
estate->eval_econtext = CreateExprContext(estate->simple_eval_estate);
|
2007-01-28 17:15:49 +01:00
|
|
|
|
2009-04-09 04:57:53 +02:00
|
|
|
/*
|
|
|
|
* Make a stack entry so we can clean up the econtext at subxact end.
|
|
|
|
* Stack entries are kept in TopTransactionContext for simplicity.
|
|
|
|
*/
|
|
|
|
entry = (SimpleEcontextStackEntry *)
|
|
|
|
MemoryContextAlloc(TopTransactionContext,
|
|
|
|
sizeof(SimpleEcontextStackEntry));
|
2007-01-28 17:15:49 +01:00
|
|
|
|
2009-04-09 04:57:53 +02:00
|
|
|
entry->stack_econtext = estate->eval_econtext;
|
|
|
|
entry->xact_subxid = GetCurrentSubTransactionId();
|
2007-01-28 17:15:49 +01:00
|
|
|
|
2009-04-09 04:57:53 +02:00
|
|
|
entry->next = simple_econtext_stack;
|
|
|
|
simple_econtext_stack = entry;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* plpgsql_destroy_econtext --- destroy function's econtext
|
|
|
|
*
|
|
|
|
* We check that it matches the top stack entry, and destroy the stack
|
|
|
|
* entry along with the context.
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
plpgsql_destroy_econtext(PLpgSQL_execstate *estate)
|
|
|
|
{
|
|
|
|
SimpleEcontextStackEntry *next;
|
|
|
|
|
|
|
|
Assert(simple_econtext_stack != NULL);
|
|
|
|
Assert(simple_econtext_stack->stack_econtext == estate->eval_econtext);
|
|
|
|
|
|
|
|
next = simple_econtext_stack->next;
|
|
|
|
pfree(simple_econtext_stack);
|
|
|
|
simple_econtext_stack = next;
|
|
|
|
|
2009-07-18 21:15:42 +02:00
|
|
|
FreeExprContext(estate->eval_econtext, true);
|
2009-04-09 04:57:53 +02:00
|
|
|
estate->eval_econtext = NULL;
|
2007-01-28 17:15:49 +01:00
|
|
|
}
|
|
|
|
|
2003-09-29 01:37:45 +02:00
|
|
|
/*
|
2004-09-16 18:58:44 +02:00
|
|
|
* plpgsql_xact_cb --- post-transaction-commit-or-abort cleanup
|
2003-09-29 01:37:45 +02:00
|
|
|
*
|
2007-01-28 17:15:49 +01:00
|
|
|
* If a simple-expression EState was created in the current transaction,
|
2006-03-02 06:34:12 +01:00
|
|
|
* it has to be cleaned up.
|
2003-09-29 01:37:45 +02:00
|
|
|
*/
|
|
|
|
void
|
2004-09-16 18:58:44 +02:00
|
|
|
plpgsql_xact_cb(XactEvent event, void *arg)
|
2003-09-29 01:37:45 +02:00
|
|
|
{
|
2004-09-16 18:58:44 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If we are doing a clean transaction shutdown, free the EState (so that
|
|
|
|
* any remaining resources will be released correctly). In an abort, we
|
|
|
|
* expect the regular abort recovery procedures to release everything of
|
2009-04-09 04:57:53 +02:00
|
|
|
* interest.
|
2004-09-16 18:58:44 +02:00
|
|
|
*/
|
2013-02-15 02:35:08 +01:00
|
|
|
if (event == XACT_EVENT_COMMIT || event == XACT_EVENT_PREPARE)
|
2007-01-28 17:15:49 +01:00
|
|
|
{
|
2009-04-09 04:57:53 +02:00
|
|
|
/* Shouldn't be any econtext stack entries left at commit */
|
|
|
|
Assert(simple_econtext_stack == NULL);
|
|
|
|
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
if (shared_simple_eval_estate)
|
|
|
|
FreeExecutorState(shared_simple_eval_estate);
|
|
|
|
shared_simple_eval_estate = NULL;
|
2007-01-28 17:15:49 +01:00
|
|
|
}
|
2013-02-15 02:35:08 +01:00
|
|
|
else if (event == XACT_EVENT_ABORT)
|
2009-04-09 04:57:53 +02:00
|
|
|
{
|
|
|
|
simple_econtext_stack = NULL;
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
shared_simple_eval_estate = NULL;
|
2009-04-09 04:57:53 +02:00
|
|
|
}
|
2007-01-28 17:15:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* plpgsql_subxact_cb --- post-subtransaction-commit-or-abort cleanup
|
|
|
|
*
|
2009-04-09 04:57:53 +02:00
|
|
|
* Make sure any simple-expression econtexts created in the current
|
|
|
|
* subtransaction get cleaned up. We have to do this explicitly because
|
Prevent leakage of cached plans and execution trees in plpgsql DO blocks.
plpgsql likes to cache query plans and simple-expression execution state
trees across calls. This is a considerable win for multiple executions
of the same function. However, it's useless for DO blocks, since by
definition those are executed only once and discarded. Nonetheless,
we were allowing a DO block's expression execution trees to survive
until end of transaction, resulting in a significant intra-transaction
memory leak, as reported by Yeb Havinga. Worse, if the DO block exited
with an error, the compiled form of the block's code was leaked till
end of session --- along with subsidiary plancache entries.
To fix, make DO blocks keep their expression execution trees in a private
EState that's deleted at exit from the block, and add a PG_TRY block
to plpgsql_inline_handler to make sure that memory cleanup happens
even on error exits. Also add a regression test covering error handling
in a DO block, because my first try at this broke that. (The test is
not meant to prove that we don't leak memory anymore, though it could
be used for that with a much larger loop count.)
Ideally we'd back-patch this into all versions supporting DO blocks;
but the patch needs to add a field to struct PLpgSQL_execstate, and that
would break ABI compatibility for third-party plugins such as the plpgsql
debugger. Given the small number of complaints so far, fixing this in
HEAD only seems like an acceptable choice.
2013-11-15 19:52:03 +01:00
|
|
|
* no other code knows which econtexts belong to which level of subxact.
|
2007-01-28 17:15:49 +01:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
plpgsql_subxact_cb(SubXactEvent event, SubTransactionId mySubid,
|
|
|
|
SubTransactionId parentSubid, void *arg)
|
|
|
|
{
|
2013-02-15 02:35:08 +01:00
|
|
|
if (event == SUBXACT_EVENT_COMMIT_SUB || event == SUBXACT_EVENT_ABORT_SUB)
|
2007-01-28 17:15:49 +01:00
|
|
|
{
|
2013-02-15 02:35:08 +01:00
|
|
|
while (simple_econtext_stack != NULL &&
|
|
|
|
simple_econtext_stack->xact_subxid == mySubid)
|
|
|
|
{
|
|
|
|
SimpleEcontextStackEntry *next;
|
2007-11-15 22:14:46 +01:00
|
|
|
|
2013-02-15 02:35:08 +01:00
|
|
|
FreeExprContext(simple_econtext_stack->stack_econtext,
|
|
|
|
(event == SUBXACT_EVENT_COMMIT_SUB));
|
|
|
|
next = simple_econtext_stack->next;
|
|
|
|
pfree(simple_econtext_stack);
|
|
|
|
simple_econtext_stack = next;
|
|
|
|
}
|
2007-01-28 17:15:49 +01:00
|
|
|
}
|
2003-09-29 01:37:45 +02:00
|
|
|
}
|
2005-06-10 18:23:11 +02:00
|
|
|
|
2007-02-08 19:37:30 +01:00
|
|
|
/*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* assign_simple_var --- assign a new value to any VAR datum.
|
2007-02-08 19:37:30 +01:00
|
|
|
*
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
* This should be the only mechanism for assignment to simple variables,
|
|
|
|
* lest we forget to update the paramLI image.
|
2007-02-08 19:37:30 +01:00
|
|
|
*/
|
2005-06-10 18:23:11 +02:00
|
|
|
static void
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(PLpgSQL_execstate *estate, PLpgSQL_var *var,
|
|
|
|
Datum newvalue, bool isnull, bool freeable)
|
2005-06-10 18:23:11 +02:00
|
|
|
{
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
ParamExternData *prm;
|
|
|
|
|
|
|
|
Assert(var->dtype == PLPGSQL_DTYPE_VAR);
|
|
|
|
/* Free the old value if needed */
|
2005-06-10 18:23:11 +02:00
|
|
|
if (var->freeval)
|
|
|
|
{
|
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
|
|
|
if (DatumIsReadWriteExpandedObject(var->value,
|
|
|
|
var->isnull,
|
|
|
|
var->datatype->typlen))
|
|
|
|
DeleteExpandedObject(var->value);
|
|
|
|
else
|
|
|
|
pfree(DatumGetPointer(var->value));
|
2005-06-10 18:23:11 +02:00
|
|
|
}
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
/* Assign new value to datum */
|
|
|
|
var->value = newvalue;
|
|
|
|
var->isnull = isnull;
|
|
|
|
var->freeval = freeable;
|
|
|
|
/* And update the image in the common parameter list */
|
|
|
|
prm = &estate->paramLI->params[var->dno];
|
|
|
|
prm->value = MakeExpandedObjectReadOnly(newvalue,
|
|
|
|
isnull,
|
|
|
|
var->datatype->typlen);
|
|
|
|
prm->isnull = isnull;
|
|
|
|
/* these might be set already, but let's be sure */
|
|
|
|
prm->pflags = PARAM_FLAG_CONST;
|
|
|
|
prm->ptype = var->datatype->typoid;
|
2005-06-10 18:23:11 +02:00
|
|
|
}
|
2008-04-01 05:51:09 +02:00
|
|
|
|
2008-04-07 01:43:29 +02:00
|
|
|
/*
|
|
|
|
* free old value of a text variable and assign new value from C string
|
|
|
|
*/
|
|
|
|
static void
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_text_var(PLpgSQL_execstate *estate, PLpgSQL_var *var, const char *str)
|
2008-04-07 01:43:29 +02:00
|
|
|
{
|
Further reduce overhead for passing plpgsql variables to the executor.
This builds on commit 21dcda2713656a7483e3280ac9d2ada20a87a9a9 by keeping
a plpgsql function's shared ParamListInfo's entries for simple variables
(PLPGSQL_DTYPE_VARs) valid at all times. That adds a few cycles to each
assignment to such variables, but saves significantly more cycles each time
they are used; so except in the pathological case of many dead stores, this
should always be a win. Initial testing says it's good for about a 10%
speedup of simple calculations; more in large functions with many datums.
We can't use this method for row/record references unfortunately, so what
we do for those is reset those ParamListInfo slots after use; which we
can skip doing unless some of them were actually evaluated during the
previous evaluation call. So this should frequently be a win as well,
while worst case is that it's similar cost to the previous approach.
Also, closer study suggests that the previous method of instantiating a
new ParamListInfo array per evaluation is actually probably optimal for
cursor-opening executor calls. The reason is that whatever is visible in
the array is going to get copied into the cursor portal via copyParamList.
So if we used the function's main ParamListInfo for those calls, we'd end
up with all of its DTYPE_VAR vars getting copied, which might well include
large pass-by-reference values that the cursor actually has no need for.
To avoid a possible net degradation in cursor cases, go back to creating
and filling a private ParamListInfo in those cases (which therefore will be
exactly the same speed as before 21dcda271365). We still get some benefit
out of this though, because this approach means that we only have to defend
against copyParamList's try-to-fetch-every-slot behavior in the case of an
unshared ParamListInfo; so plpgsql_param_fetch() can skip testing
expr->paramnos in the common case.
To ensure that the main ParamListInfo's image of a DTYPE_VAR datum is
always valid, all assignments to such variables are now funneled through
assign_simple_var(). But this makes for cleaner and shorter code anyway.
2015-07-05 18:57:17 +02:00
|
|
|
assign_simple_var(estate, var, CStringGetTextDatum(str), false, true);
|
2008-04-07 01:43:29 +02:00
|
|
|
}
|
|
|
|
|
2008-04-01 05:51:09 +02:00
|
|
|
/*
|
|
|
|
* exec_eval_using_params --- evaluate params of USING clause
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
*
|
|
|
|
* The result data structure is created in the stmt_mcontext, and should
|
|
|
|
* be freed by resetting that context.
|
2008-04-01 05:51:09 +02:00
|
|
|
*/
|
|
|
|
static PreparedParamsData *
|
|
|
|
exec_eval_using_params(PLpgSQL_execstate *estate, List *params)
|
|
|
|
{
|
|
|
|
PreparedParamsData *ppd;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
|
2008-04-01 05:51:09 +02:00
|
|
|
int nargs;
|
|
|
|
int i;
|
|
|
|
ListCell *lc;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
ppd = (PreparedParamsData *)
|
|
|
|
MemoryContextAlloc(stmt_mcontext, sizeof(PreparedParamsData));
|
2008-04-01 05:51:09 +02:00
|
|
|
nargs = list_length(params);
|
|
|
|
|
|
|
|
ppd->nargs = nargs;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
ppd->types = (Oid *)
|
|
|
|
MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Oid));
|
|
|
|
ppd->values = (Datum *)
|
|
|
|
MemoryContextAlloc(stmt_mcontext, nargs * sizeof(Datum));
|
|
|
|
ppd->nulls = (char *)
|
|
|
|
MemoryContextAlloc(stmt_mcontext, nargs * sizeof(char));
|
2008-04-01 05:51:09 +02:00
|
|
|
|
|
|
|
i = 0;
|
|
|
|
foreach(lc, params)
|
|
|
|
{
|
|
|
|
PLpgSQL_expr *param = (PLpgSQL_expr *) lfirst(lc);
|
2009-06-11 16:49:15 +02:00
|
|
|
bool isnull;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 ppdtypmod;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
2008-04-01 05:51:09 +02:00
|
|
|
|
|
|
|
ppd->values[i] = exec_eval_expr(estate, param,
|
|
|
|
&isnull,
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
&ppd->types[i],
|
|
|
|
&ppdtypmod);
|
2008-04-01 05:51:09 +02:00
|
|
|
ppd->nulls[i] = isnull ? 'n' : ' ';
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
|
|
|
|
oldcontext = MemoryContextSwitchTo(stmt_mcontext);
|
2008-04-01 05:51:09 +02:00
|
|
|
|
2010-08-19 18:54:43 +02:00
|
|
|
if (ppd->types[i] == UNKNOWNOID)
|
|
|
|
{
|
|
|
|
/*
|
2010-08-19 19:31:43 +02:00
|
|
|
* Treat 'unknown' parameters as text, since that's what most
|
|
|
|
* people would expect. SPI_execute_with_args can coerce unknown
|
|
|
|
* constants in a more intelligent way, but not unknown Params.
|
|
|
|
* This code also takes care of copying into the right context.
|
|
|
|
* Note we assume 'unknown' has the representation of C-string.
|
2010-08-19 18:54:43 +02:00
|
|
|
*/
|
|
|
|
ppd->types[i] = TEXTOID;
|
|
|
|
if (!isnull)
|
2010-08-19 19:31:43 +02:00
|
|
|
ppd->values[i] = CStringGetTextDatum(DatumGetCString(ppd->values[i]));
|
2010-08-19 18:54:43 +02:00
|
|
|
}
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* pass-by-ref non null values must be copied into stmt_mcontext */
|
2010-08-19 18:54:43 +02:00
|
|
|
else if (!isnull)
|
2008-04-01 05:51:09 +02:00
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
int16 typLen;
|
|
|
|
bool typByVal;
|
2008-04-01 05:51:09 +02:00
|
|
|
|
|
|
|
get_typlenbyval(ppd->types[i], &typLen, &typByVal);
|
|
|
|
if (!typByVal)
|
|
|
|
ppd->values[i] = datumCopy(ppd->values[i], typByVal, typLen);
|
|
|
|
}
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2008-04-01 05:51:09 +02:00
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ppd;
|
|
|
|
}
|
|
|
|
|
2008-05-03 02:11:36 +02:00
|
|
|
/*
|
|
|
|
* Open portal for dynamic query
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
*
|
|
|
|
* Caution: this resets the stmt_mcontext at exit. We might eventually need
|
|
|
|
* to move that responsibility to the callers, but currently no caller needs
|
|
|
|
* to have statement-lifetime temp data that survives past this, so it's
|
|
|
|
* simpler to do it here.
|
2008-05-03 02:11:36 +02:00
|
|
|
*/
|
|
|
|
static Portal
|
2010-01-19 02:35:31 +01:00
|
|
|
exec_dynquery_with_params(PLpgSQL_execstate *estate,
|
|
|
|
PLpgSQL_expr *dynquery,
|
|
|
|
List *params,
|
|
|
|
const char *portalname,
|
|
|
|
int cursorOptions)
|
2008-05-03 02:11:36 +02:00
|
|
|
{
|
|
|
|
Portal portal;
|
|
|
|
Datum query;
|
|
|
|
bool isnull;
|
|
|
|
Oid restype;
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
int32 restypmod;
|
2008-05-03 02:11:36 +02:00
|
|
|
char *querystr;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext stmt_mcontext = get_stmt_mcontext(estate);
|
2008-05-03 02:11:36 +02:00
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Evaluate the string expression after the EXECUTE keyword. Its result is
|
|
|
|
* the querystring we have to execute.
|
2008-05-03 02:11:36 +02:00
|
|
|
*/
|
Track typmods in plpgsql expression evaluation and assignment.
The main value of this change is to avoid expensive I/O conversions when
assigning to a variable that has a typmod specification, if the value
to be assigned is already known to have the right typmod. This is
particularly valuable for arrays with typmod specifications; formerly,
in an assignment to an array element the entire array would invariably
get put through double I/O conversion to check the typmod, to absolutely
no purpose since we'd already properly coerced the new element value.
Extracted from my "expanded arrays" patch; this seems worth committing
separately, whatever becomes of that patch, since it's really an
independent issue.
As long as we're changing the function signatures, take the opportunity
to rationalize the argument lists of exec_assign_value, exec_cast_value,
and exec_simple_cast_value; that is, put the arguments into a saner order,
and get rid of the bizarre choice to pass exec_assign_value's isNull flag
by reference.
2015-02-28 20:34:35 +01:00
|
|
|
query = exec_eval_expr(estate, dynquery, &isnull, &restype, &restypmod);
|
2008-05-03 02:11:36 +02:00
|
|
|
if (isnull)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
|
2009-02-18 12:33:04 +01:00
|
|
|
errmsg("query string argument of EXECUTE is null")));
|
2008-05-03 02:11:36 +02:00
|
|
|
|
|
|
|
/* Get the C-String representation */
|
2012-02-12 00:06:24 +01:00
|
|
|
querystr = convert_value_to_string(estate, query, restype);
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
/* copy it into the stmt_mcontext before we clean up */
|
|
|
|
querystr = MemoryContextStrdup(stmt_mcontext, querystr);
|
2008-05-03 02:11:36 +02:00
|
|
|
|
|
|
|
exec_eval_cleanup(estate);
|
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Open an implicit cursor for the query. We use
|
|
|
|
* SPI_cursor_open_with_args even when there are no params, because this
|
|
|
|
* avoids making and freeing one copy of the plan.
|
2008-05-03 02:11:36 +02:00
|
|
|
*/
|
|
|
|
if (params)
|
|
|
|
{
|
|
|
|
PreparedParamsData *ppd;
|
|
|
|
|
|
|
|
ppd = exec_eval_using_params(estate, params);
|
2010-01-19 02:35:31 +01:00
|
|
|
portal = SPI_cursor_open_with_args(portalname,
|
2008-05-03 02:11:36 +02:00
|
|
|
querystr,
|
|
|
|
ppd->nargs, ppd->types,
|
|
|
|
ppd->values, ppd->nulls,
|
2010-02-26 03:01:40 +01:00
|
|
|
estate->readonly_func,
|
2010-01-19 02:35:31 +01:00
|
|
|
cursorOptions);
|
2008-05-03 02:11:36 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-01-19 02:35:31 +01:00
|
|
|
portal = SPI_cursor_open_with_args(portalname,
|
2008-05-03 02:11:36 +02:00
|
|
|
querystr,
|
|
|
|
0, NULL,
|
|
|
|
NULL, NULL,
|
2010-02-26 03:01:40 +01:00
|
|
|
estate->readonly_func,
|
2010-01-19 02:35:31 +01:00
|
|
|
cursorOptions);
|
2008-05-03 02:11:36 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (portal == NULL)
|
|
|
|
elog(ERROR, "could not open implicit cursor for query \"%s\": %s",
|
|
|
|
querystr, SPI_result_code_string(SPI_result));
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
|
|
|
|
/* Release transient data */
|
|
|
|
MemoryContextReset(stmt_mcontext);
|
2008-05-03 02:11:36 +02:00
|
|
|
|
|
|
|
return portal;
|
|
|
|
}
|
2013-10-07 21:38:49 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Return a formatted string with information about an expression's parameters,
|
|
|
|
* or NULL if the expression does not take any parameters.
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* The result is in the eval_mcontext.
|
2013-10-07 21:38:49 +02:00
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
format_expr_params(PLpgSQL_execstate *estate,
|
|
|
|
const PLpgSQL_expr *expr)
|
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
int paramno;
|
|
|
|
int dno;
|
2013-10-07 21:38:49 +02:00
|
|
|
StringInfoData paramstr;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
2013-10-07 21:38:49 +02:00
|
|
|
|
|
|
|
if (!expr->paramnos)
|
|
|
|
return NULL;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
|
|
|
|
2013-10-07 21:38:49 +02:00
|
|
|
initStringInfo(¶mstr);
|
|
|
|
paramno = 0;
|
2014-11-28 19:37:25 +01:00
|
|
|
dno = -1;
|
|
|
|
while ((dno = bms_next_member(expr->paramnos, dno)) >= 0)
|
2013-10-07 21:38:49 +02:00
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
Datum paramdatum;
|
|
|
|
Oid paramtypeid;
|
|
|
|
bool paramisnull;
|
|
|
|
int32 paramtypmod;
|
2013-10-07 21:38:49 +02:00
|
|
|
PLpgSQL_var *curvar;
|
|
|
|
|
|
|
|
curvar = (PLpgSQL_var *) estate->datums[dno];
|
|
|
|
|
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
|
|
|
exec_eval_datum(estate, (PLpgSQL_datum *) curvar,
|
|
|
|
¶mtypeid, ¶mtypmod,
|
|
|
|
¶mdatum, ¶misnull);
|
2013-10-07 21:38:49 +02:00
|
|
|
|
|
|
|
appendStringInfo(¶mstr, "%s%s = ",
|
|
|
|
paramno > 0 ? ", " : "",
|
|
|
|
curvar->refname);
|
|
|
|
|
|
|
|
if (paramisnull)
|
|
|
|
appendStringInfoString(¶mstr, "NULL");
|
|
|
|
else
|
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
char *value = convert_value_to_string(estate, paramdatum, paramtypeid);
|
|
|
|
char *p;
|
|
|
|
|
2013-10-07 21:38:49 +02:00
|
|
|
appendStringInfoCharMacro(¶mstr, '\'');
|
|
|
|
for (p = value; *p; p++)
|
|
|
|
{
|
|
|
|
if (*p == '\'') /* double single quotes */
|
|
|
|
appendStringInfoCharMacro(¶mstr, *p);
|
|
|
|
appendStringInfoCharMacro(¶mstr, *p);
|
|
|
|
}
|
|
|
|
appendStringInfoCharMacro(¶mstr, '\'');
|
|
|
|
}
|
|
|
|
|
|
|
|
paramno++;
|
|
|
|
}
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2013-10-07 21:38:49 +02:00
|
|
|
return paramstr.data;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Return a formatted string with information about PreparedParamsData, or NULL
|
2013-12-13 18:58:48 +01:00
|
|
|
* if there are no parameters.
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
* The result is in the eval_mcontext.
|
2013-10-07 21:38:49 +02:00
|
|
|
*/
|
|
|
|
static char *
|
|
|
|
format_preparedparamsdata(PLpgSQL_execstate *estate,
|
|
|
|
const PreparedParamsData *ppd)
|
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
int paramno;
|
2013-10-07 21:38:49 +02:00
|
|
|
StringInfoData paramstr;
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContext oldcontext;
|
2013-10-07 21:38:49 +02:00
|
|
|
|
|
|
|
if (!ppd)
|
|
|
|
return NULL;
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(get_eval_mcontext(estate));
|
|
|
|
|
2013-10-07 21:38:49 +02:00
|
|
|
initStringInfo(¶mstr);
|
|
|
|
for (paramno = 0; paramno < ppd->nargs; paramno++)
|
|
|
|
{
|
|
|
|
appendStringInfo(¶mstr, "%s$%d = ",
|
|
|
|
paramno > 0 ? ", " : "",
|
|
|
|
paramno + 1);
|
|
|
|
|
|
|
|
if (ppd->nulls[paramno] == 'n')
|
|
|
|
appendStringInfoString(¶mstr, "NULL");
|
|
|
|
else
|
|
|
|
{
|
2014-05-06 18:12:18 +02:00
|
|
|
char *value = convert_value_to_string(estate, ppd->values[paramno], ppd->types[paramno]);
|
|
|
|
char *p;
|
|
|
|
|
2013-10-07 21:38:49 +02:00
|
|
|
appendStringInfoCharMacro(¶mstr, '\'');
|
|
|
|
for (p = value; *p; p++)
|
|
|
|
{
|
|
|
|
if (*p == '\'') /* double single quotes */
|
|
|
|
appendStringInfoCharMacro(¶mstr, *p);
|
|
|
|
appendStringInfoCharMacro(¶mstr, *p);
|
|
|
|
}
|
|
|
|
appendStringInfoCharMacro(¶mstr, '\'');
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Improve plpgsql's memory management to fix some function-lifespan leaks.
In some cases, exiting out of a plpgsql statement due to an error, then
catching the error in a surrounding exception block, led to leakage of
temporary data the statement was working with, because we kept all such
data in the function-lifespan SPI Proc context. Iterating such behavior
many times within one function call thus led to noticeable memory bloat.
To fix, create an additional memory context meant to have statement
lifespan. Since many plpgsql statements, particularly the simpler/more
common ones, don't need this, create it only on demand. Reset this context
at the end of any statement that uses it, and arrange for exception cleanup
to reset it too, thereby fixing the memory-leak issue. Allow a stack of
such contexts to exist to handle cases where a compound statement needs
statement-lifespan data that persists across calls of inner statements.
While at it, clean up code and improve comments referring to the existing
short-term memory context, which by plpgsql convention is the per-tuple
context of the eval_econtext ExprContext. We now uniformly refer to that
as the eval_mcontext, whereas the new statement-lifespan memory contexts
are called stmt_mcontext.
This change adds some context-creation overhead, but on the other hand
it allows removal of some retail pfree's in favor of context resets.
On balance it seems to be about a wash performance-wise.
In principle this is a bug fix, but it seems too invasive for a back-patch,
and the infrequency of complaints weighs against taking the risk in the
back branches. So we'll fix it only in HEAD, at least for now.
Tom Lane, reviewed by Pavel Stehule
Discussion: <17863.1469142152@sss.pgh.pa.us>
2016-08-17 20:51:10 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2013-10-07 21:38:49 +02:00
|
|
|
return paramstr.data;
|
|
|
|
}
|