1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* functions.c
|
2003-07-28 20:33:18 +02:00
|
|
|
* Execution of SQL-language functions
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2020-01-01 18:21:45 +01:00
|
|
|
* Portions Copyright (c) 1996-2020, PostgreSQL Global Development Group
|
2000-01-26 06:58:53 +01:00
|
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*
|
|
|
|
* IDENTIFICATION
|
2010-09-20 22:08:53 +02:00
|
|
|
* src/backend/executor/functions.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
|
|
|
#include "postgres.h"
|
|
|
|
|
2012-08-30 22:15:44 +02:00
|
|
|
#include "access/htup_details.h"
|
2006-07-13 18:49:20 +02:00
|
|
|
#include "access/xact.h"
|
2000-08-24 05:29:15 +02:00
|
|
|
#include "catalog/pg_proc.h"
|
|
|
|
#include "catalog/pg_type.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "executor/functions.h"
|
2005-04-01 00:46:33 +02:00
|
|
|
#include "funcapi.h"
|
2008-10-31 20:37:56 +01:00
|
|
|
#include "miscadmin.h"
|
2008-03-18 23:04:14 +01:00
|
|
|
#include "nodes/makefuncs.h"
|
2008-08-26 00:42:34 +02:00
|
|
|
#include "nodes/nodeFuncs.h"
|
2004-10-07 20:38:51 +02:00
|
|
|
#include "parser/parse_coerce.h"
|
2020-04-14 23:30:13 +02:00
|
|
|
#include "parser/parse_collate.h"
|
2012-02-05 01:23:49 +01:00
|
|
|
#include "parser/parse_func.h"
|
2013-03-03 23:39:58 +01:00
|
|
|
#include "storage/proc.h"
|
1996-10-26 06:15:05 +02:00
|
|
|
#include "tcop/utility.h"
|
2000-08-24 05:29:15 +02:00
|
|
|
#include "utils/builtins.h"
|
2004-04-01 23:28:47 +02:00
|
|
|
#include "utils/datum.h"
|
2003-07-01 02:04:39 +02:00
|
|
|
#include "utils/lsyscache.h"
|
2013-03-03 23:39:58 +01:00
|
|
|
#include "utils/memutils.h"
|
2008-03-26 19:48:59 +01:00
|
|
|
#include "utils/snapmgr.h"
|
2000-08-24 05:29:15 +02:00
|
|
|
#include "utils/syscache.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
|
|
|
* Specialized DestReceiver for collecting query output in a SQL function
|
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
|
|
|
DestReceiver pub; /* publicly-known function pointers */
|
|
|
|
Tuplestorestate *tstore; /* where to put result tuples */
|
|
|
|
MemoryContext cxt; /* context containing tstore */
|
|
|
|
JunkFilter *filter; /* filter to convert tuple type */
|
|
|
|
} DR_sqlfunction;
|
|
|
|
|
2000-08-24 05:29:15 +02:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* We have an execution_state record for each query in a function. Each
|
2007-02-20 18:32:18 +01:00
|
|
|
* record contains a plantree for its query. If the query is currently in
|
|
|
|
* F_EXEC_RUN state then there's a QueryDesc too.
|
2011-03-01 05:27:18 +01:00
|
|
|
*
|
|
|
|
* The "next" fields chain together all the execution_state records generated
|
|
|
|
* from a single original parsetree. (There will only be more than one in
|
|
|
|
* case of rule expansion of the original parsetree.)
|
2000-08-24 05:29:15 +02:00
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
typedef enum
|
|
|
|
{
|
2001-10-28 07:26:15 +01:00
|
|
|
F_EXEC_START, F_EXEC_RUN, F_EXEC_DONE
|
1997-09-08 23:56:23 +02:00
|
|
|
} ExecStatus;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
typedef struct execution_state
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
struct execution_state *next;
|
1997-09-08 04:41:22 +02:00
|
|
|
ExecStatus status;
|
2008-10-31 20:37:56 +01:00
|
|
|
bool setsResult; /* true if this query produces func's result */
|
|
|
|
bool lazyEval; /* true if should fetch one row at a time */
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
PlannedStmt *stmt; /* plan for this query */
|
2002-12-05 16:50:39 +01:00
|
|
|
QueryDesc *qd; /* null unless status == RUN */
|
1997-09-08 23:56:23 +02:00
|
|
|
} execution_state;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2000-08-24 05:29:15 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* An SQLFunctionCache record is built during the first call,
|
|
|
|
* and linked to from the fn_extra field of the FmgrInfo struct.
|
2008-10-31 20:37:56 +01:00
|
|
|
*
|
|
|
|
* Note that currently this has only the lifespan of the calling query.
|
2013-03-03 23:39:58 +01:00
|
|
|
* Someday we should rewrite this code to use plancache.c to save parse/plan
|
|
|
|
* results for longer than that.
|
|
|
|
*
|
|
|
|
* Physically, though, the data has the lifespan of the FmgrInfo that's used
|
|
|
|
* to call the function, and there are cases (particularly with indexes)
|
|
|
|
* where the FmgrInfo might survive across transactions. We cannot assume
|
|
|
|
* that the parse/plan trees are good for longer than the (sub)transaction in
|
|
|
|
* which parsing was done, so we must mark the record with the LXID/subxid of
|
|
|
|
* its creation time, and regenerate everything if that's obsolete. To avoid
|
|
|
|
* memory leakage when we do have to regenerate things, all the data is kept
|
|
|
|
* in a sub-context of the FmgrInfo's fn_mcxt.
|
2000-08-24 05:29:15 +02:00
|
|
|
*/
|
|
|
|
typedef struct
|
|
|
|
{
|
2010-03-19 23:54:41 +01:00
|
|
|
char *fname; /* function name (for error msgs) */
|
2007-03-13 01:33:44 +01:00
|
|
|
char *src; /* function body text (for error msgs) */
|
|
|
|
|
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
|
|
|
SQLFunctionParseInfoPtr pinfo; /* data for parser callback hooks */
|
2011-03-25 01:30:14 +01:00
|
|
|
|
2004-07-15 15:51:38 +02:00
|
|
|
Oid rettype; /* actual return type */
|
2007-02-02 01:02:55 +01:00
|
|
|
int16 typlen; /* length of the return type */
|
2000-08-24 05:29:15 +02:00
|
|
|
bool typbyval; /* true if return type is pass by value */
|
2008-10-31 20:37:56 +01:00
|
|
|
bool returnsSet; /* true if returning multiple rows */
|
2004-07-15 15:51:38 +02:00
|
|
|
bool returnsTuple; /* true if returning whole tuple result */
|
2002-05-12 22:10:05 +02:00
|
|
|
bool shutdown_reg; /* true if registered shutdown callback */
|
2004-09-13 22:10:13 +02:00
|
|
|
bool readonly_func; /* true to run in "read only" mode */
|
2008-10-31 20:37:56 +01:00
|
|
|
bool lazyEval; /* true if using lazyEval for result query */
|
2000-08-24 05:29:15 +02:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
ParamListInfo paramLI; /* Param list representing current args */
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
Tuplestorestate *tstore; /* where we accumulate result tuples */
|
|
|
|
|
|
|
|
JunkFilter *junkFilter; /* will be NULL if function returns VOID */
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
/*
|
|
|
|
* func_state is a List of execution_state records, each of which is the
|
|
|
|
* first for its original parsetree, with any additional records chained
|
|
|
|
* to it via the "next" fields. This sublist structure is needed to keep
|
|
|
|
* track of where the original query boundaries are.
|
|
|
|
*/
|
|
|
|
List *func_state;
|
2013-03-03 23:39:58 +01:00
|
|
|
|
|
|
|
MemoryContext fcontext; /* memory context holding this struct and all
|
|
|
|
* subsidiary data */
|
|
|
|
|
|
|
|
LocalTransactionId lxid; /* lxid in which cache was made */
|
|
|
|
SubTransactionId subxid; /* subxid in which cache was made */
|
2000-08-24 05:29:15 +02:00
|
|
|
} SQLFunctionCache;
|
|
|
|
|
|
|
|
typedef SQLFunctionCache *SQLFunctionCachePtr;
|
|
|
|
|
2011-03-25 01:30:14 +01:00
|
|
|
/*
|
|
|
|
* Data structure needed by the parser callback hooks to resolve parameter
|
|
|
|
* references during parsing of a SQL function's body. This is separate from
|
|
|
|
* SQLFunctionCache since we sometimes do parsing separately from execution.
|
|
|
|
*/
|
|
|
|
typedef struct SQLFunctionParseInfo
|
|
|
|
{
|
2012-02-05 01:23:49 +01:00
|
|
|
char *fname; /* function's name */
|
2011-03-25 01:30:14 +01:00
|
|
|
int nargs; /* number of input arguments */
|
2012-02-05 01:23:49 +01:00
|
|
|
Oid *argtypes; /* resolved types of input arguments */
|
|
|
|
char **argnames; /* names of input arguments; NULL if none */
|
|
|
|
/* Note that argnames[i] can be NULL, if some args are unnamed */
|
2011-03-25 01:30:14 +01:00
|
|
|
Oid collation; /* function's input collation, if known */
|
2017-06-21 20:39:04 +02:00
|
|
|
} SQLFunctionParseInfo;
|
2011-03-25 01:30:14 +01:00
|
|
|
|
2000-08-24 05:29:15 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
/* non-export function prototypes */
|
2011-03-25 01:30:14 +01:00
|
|
|
static Node *sql_fn_param_ref(ParseState *pstate, ParamRef *pref);
|
2012-02-05 01:23:49 +01:00
|
|
|
static Node *sql_fn_post_column_ref(ParseState *pstate,
|
2019-05-22 19:04:48 +02:00
|
|
|
ColumnRef *cref, Node *var);
|
2012-02-05 01:23:49 +01:00
|
|
|
static Node *sql_fn_make_param(SQLFunctionParseInfoPtr pinfo,
|
2019-05-22 19:04:48 +02:00
|
|
|
int paramno, int location);
|
2012-02-05 01:23:49 +01:00
|
|
|
static Node *sql_fn_resolve_param_name(SQLFunctionParseInfoPtr pinfo,
|
2019-05-22 19:04:48 +02:00
|
|
|
const char *paramname, int location);
|
2011-03-01 05:27:18 +01:00
|
|
|
static List *init_execution_state(List *queryTree_list,
|
2019-05-22 19:04:48 +02:00
|
|
|
SQLFunctionCachePtr fcache,
|
|
|
|
bool lazyEvalOK);
|
2020-01-08 17:07:53 +01:00
|
|
|
static void init_sql_fcache(FunctionCallInfo fcinfo, Oid collation, bool lazyEvalOK);
|
2002-12-05 16:50:39 +01:00
|
|
|
static void postquel_start(execution_state *es, SQLFunctionCachePtr fcache);
|
2008-10-31 22:07:55 +01:00
|
|
|
static bool postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache);
|
2005-04-10 20:04:20 +02:00
|
|
|
static void postquel_end(execution_state *es);
|
2002-12-05 16:50:39 +01:00
|
|
|
static void postquel_sub_params(SQLFunctionCachePtr fcache,
|
2019-05-22 19:04:48 +02:00
|
|
|
FunctionCallInfo fcinfo);
|
2008-10-31 20:37:56 +01:00
|
|
|
static Datum postquel_get_single_result(TupleTableSlot *slot,
|
2019-05-22 19:04:48 +02:00
|
|
|
FunctionCallInfo fcinfo,
|
|
|
|
SQLFunctionCachePtr fcache,
|
|
|
|
MemoryContext resultcontext);
|
2003-07-28 20:33:18 +02:00
|
|
|
static void sql_exec_error_callback(void *arg);
|
2002-05-12 22:10:05 +02:00
|
|
|
static void ShutdownSQLFunction(Datum arg);
|
2020-01-08 17:07:53 +01:00
|
|
|
static bool coerce_fn_result_column(TargetEntry *src_tle,
|
|
|
|
Oid res_type, int32 res_typmod,
|
|
|
|
bool tlist_is_modifiable,
|
|
|
|
List **upper_tlist,
|
|
|
|
bool *upper_tlist_nontrivial);
|
2008-10-31 20:37:56 +01:00
|
|
|
static void sqlfunction_startup(DestReceiver *self, int operation, TupleDesc typeinfo);
|
2016-06-06 20:52:58 +02:00
|
|
|
static bool sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self);
|
2008-10-31 20:37:56 +01:00
|
|
|
static void sqlfunction_shutdown(DestReceiver *self);
|
|
|
|
static void sqlfunction_destroy(DestReceiver *self);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
|
2011-03-25 01:30:14 +01:00
|
|
|
/*
|
|
|
|
* Prepare the SQLFunctionParseInfo struct for parsing a SQL function body
|
|
|
|
*
|
|
|
|
* This includes resolving actual types of polymorphic arguments.
|
|
|
|
*
|
|
|
|
* call_expr can be passed as NULL, but then we will fail if there are any
|
|
|
|
* polymorphic arguments.
|
|
|
|
*/
|
|
|
|
SQLFunctionParseInfoPtr
|
|
|
|
prepare_sql_fn_parse_info(HeapTuple procedureTuple,
|
|
|
|
Node *call_expr,
|
|
|
|
Oid inputCollation)
|
|
|
|
{
|
|
|
|
SQLFunctionParseInfoPtr pinfo;
|
|
|
|
Form_pg_proc procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
|
|
|
|
int nargs;
|
|
|
|
|
|
|
|
pinfo = (SQLFunctionParseInfoPtr) palloc0(sizeof(SQLFunctionParseInfo));
|
|
|
|
|
2012-02-05 01:23:49 +01:00
|
|
|
/* Function's name (only) can be used to qualify argument names */
|
|
|
|
pinfo->fname = pstrdup(NameStr(procedureStruct->proname));
|
|
|
|
|
2011-03-25 01:30:14 +01:00
|
|
|
/* Save the function's input collation */
|
|
|
|
pinfo->collation = inputCollation;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copy input argument types from the pg_proc entry, then resolve any
|
|
|
|
* polymorphic types.
|
|
|
|
*/
|
|
|
|
pinfo->nargs = nargs = procedureStruct->pronargs;
|
|
|
|
if (nargs > 0)
|
|
|
|
{
|
|
|
|
Oid *argOidVect;
|
|
|
|
int argnum;
|
|
|
|
|
|
|
|
argOidVect = (Oid *) palloc(nargs * sizeof(Oid));
|
|
|
|
memcpy(argOidVect,
|
|
|
|
procedureStruct->proargtypes.values,
|
|
|
|
nargs * sizeof(Oid));
|
|
|
|
|
|
|
|
for (argnum = 0; argnum < nargs; argnum++)
|
|
|
|
{
|
|
|
|
Oid argtype = argOidVect[argnum];
|
|
|
|
|
|
|
|
if (IsPolymorphicType(argtype))
|
|
|
|
{
|
|
|
|
argtype = get_call_expr_argtype(call_expr, argnum);
|
|
|
|
if (argtype == InvalidOid)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
|
|
errmsg("could not determine actual type of argument declared %s",
|
|
|
|
format_type_be(argOidVect[argnum]))));
|
|
|
|
argOidVect[argnum] = argtype;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pinfo->argtypes = argOidVect;
|
|
|
|
}
|
|
|
|
|
2012-02-05 01:23:49 +01:00
|
|
|
/*
|
|
|
|
* Collect names of arguments, too, if any
|
|
|
|
*/
|
|
|
|
if (nargs > 0)
|
|
|
|
{
|
|
|
|
Datum proargnames;
|
|
|
|
Datum proargmodes;
|
|
|
|
int n_arg_names;
|
|
|
|
bool isNull;
|
|
|
|
|
|
|
|
proargnames = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple,
|
|
|
|
Anum_pg_proc_proargnames,
|
|
|
|
&isNull);
|
|
|
|
if (isNull)
|
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
|
|
|
proargnames = PointerGetDatum(NULL); /* just to be sure */
|
2012-02-05 01:23:49 +01:00
|
|
|
|
|
|
|
proargmodes = SysCacheGetAttr(PROCNAMEARGSNSP, procedureTuple,
|
|
|
|
Anum_pg_proc_proargmodes,
|
|
|
|
&isNull);
|
|
|
|
if (isNull)
|
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
|
|
|
proargmodes = PointerGetDatum(NULL); /* just to be sure */
|
2012-02-05 01:23:49 +01:00
|
|
|
|
|
|
|
n_arg_names = get_func_input_arg_names(proargnames, proargmodes,
|
|
|
|
&pinfo->argnames);
|
|
|
|
|
|
|
|
/* Paranoia: ignore the result if too few array entries */
|
|
|
|
if (n_arg_names < nargs)
|
|
|
|
pinfo->argnames = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
pinfo->argnames = NULL;
|
|
|
|
|
2011-03-25 01:30:14 +01:00
|
|
|
return pinfo;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Parser setup hook for parsing a SQL function body.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
sql_fn_parser_setup(struct ParseState *pstate, SQLFunctionParseInfoPtr pinfo)
|
|
|
|
{
|
|
|
|
pstate->p_pre_columnref_hook = NULL;
|
2012-02-05 01:23:49 +01:00
|
|
|
pstate->p_post_columnref_hook = sql_fn_post_column_ref;
|
2011-03-25 01:30:14 +01:00
|
|
|
pstate->p_paramref_hook = sql_fn_param_ref;
|
|
|
|
/* no need to use p_coerce_param_hook */
|
|
|
|
pstate->p_ref_hook_state = (void *) pinfo;
|
|
|
|
}
|
|
|
|
|
2012-02-05 01:23:49 +01:00
|
|
|
/*
|
|
|
|
* sql_fn_post_column_ref parser callback for ColumnRefs
|
|
|
|
*/
|
|
|
|
static Node *
|
|
|
|
sql_fn_post_column_ref(ParseState *pstate, ColumnRef *cref, Node *var)
|
|
|
|
{
|
|
|
|
SQLFunctionParseInfoPtr pinfo = (SQLFunctionParseInfoPtr) pstate->p_ref_hook_state;
|
|
|
|
int nnames;
|
|
|
|
Node *field1;
|
|
|
|
Node *subfield = NULL;
|
|
|
|
const char *name1;
|
|
|
|
const char *name2 = NULL;
|
|
|
|
Node *param;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Never override a table-column reference. This corresponds to
|
|
|
|
* considering the parameter names to appear in a scope outside the
|
|
|
|
* individual SQL commands, which is what we want.
|
|
|
|
*/
|
|
|
|
if (var != NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
/*----------
|
|
|
|
* The allowed syntaxes are:
|
|
|
|
*
|
|
|
|
* A A = parameter name
|
|
|
|
* A.B A = function name, B = parameter name
|
|
|
|
* OR: A = record-typed parameter name, B = field name
|
|
|
|
* (the first possibility takes precedence)
|
|
|
|
* A.B.C A = function name, B = record-typed parameter name,
|
|
|
|
* C = field name
|
2014-02-03 20:46:51 +01:00
|
|
|
* A.* Whole-row reference to composite parameter A.
|
|
|
|
* A.B.* Same, with A = function name, B = parameter name
|
|
|
|
*
|
|
|
|
* Here, it's sufficient to ignore the "*" in the last two cases --- the
|
|
|
|
* main parser will take care of expanding the whole-row reference.
|
2012-02-05 01:23:49 +01:00
|
|
|
*----------
|
|
|
|
*/
|
|
|
|
nnames = list_length(cref->fields);
|
|
|
|
|
|
|
|
if (nnames > 3)
|
|
|
|
return NULL;
|
|
|
|
|
2014-02-03 20:46:51 +01:00
|
|
|
if (IsA(llast(cref->fields), A_Star))
|
|
|
|
nnames--;
|
|
|
|
|
2012-02-05 01:23:49 +01:00
|
|
|
field1 = (Node *) linitial(cref->fields);
|
|
|
|
Assert(IsA(field1, String));
|
|
|
|
name1 = strVal(field1);
|
|
|
|
if (nnames > 1)
|
|
|
|
{
|
|
|
|
subfield = (Node *) lsecond(cref->fields);
|
|
|
|
Assert(IsA(subfield, String));
|
|
|
|
name2 = strVal(subfield);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nnames == 3)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Three-part name: if the first part doesn't match the function name,
|
|
|
|
* we can fail immediately. Otherwise, look up the second part, and
|
|
|
|
* take the third part to be a field reference.
|
|
|
|
*/
|
|
|
|
if (strcmp(name1, pinfo->fname) != 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
param = sql_fn_resolve_param_name(pinfo, name2, cref->location);
|
|
|
|
|
|
|
|
subfield = (Node *) lthird(cref->fields);
|
|
|
|
Assert(IsA(subfield, String));
|
|
|
|
}
|
|
|
|
else if (nnames == 2 && strcmp(name1, pinfo->fname) == 0)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Two-part name with first part matching function name: first see if
|
|
|
|
* second part matches any parameter name.
|
|
|
|
*/
|
|
|
|
param = sql_fn_resolve_param_name(pinfo, name2, cref->location);
|
|
|
|
|
|
|
|
if (param)
|
|
|
|
{
|
|
|
|
/* Yes, so this is a parameter reference, no subfield */
|
|
|
|
subfield = NULL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* No, so try to match as parameter name and subfield */
|
|
|
|
param = sql_fn_resolve_param_name(pinfo, name1, cref->location);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Single name, or parameter name followed by subfield */
|
|
|
|
param = sql_fn_resolve_param_name(pinfo, name1, cref->location);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!param)
|
|
|
|
return NULL; /* No match */
|
|
|
|
|
|
|
|
if (subfield)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Must be a reference to a field of a composite parameter; otherwise
|
|
|
|
* ParseFuncOrColumn will return NULL, and we'll fail back at the
|
|
|
|
* caller.
|
|
|
|
*/
|
|
|
|
param = ParseFuncOrColumn(pstate,
|
|
|
|
list_make1(subfield),
|
|
|
|
list_make1(param),
|
Disallow set-returning functions inside CASE or COALESCE.
When we reimplemented SRFs in commit 69f4b9c85, our initial choice was
to allow the behavior to vary from historical practice in cases where a
SRF call appeared within a conditional-execution construct (currently,
only CASE or COALESCE). But that was controversial to begin with, and
subsequent discussion has resulted in a consensus that it's better to
throw an error instead of executing the query differently from before,
so long as we can provide a reasonably clear error message and a way to
rewrite the query.
Hence, add a parser mechanism to allow detection of such cases during
parse analysis. The mechanism just requires storing, in the ParseState,
a pointer to the set-returning FuncExpr or OpExpr most recently emitted
by parse analysis. Then the parsing functions for CASE and COALESCE can
detect the presence of a SRF in their arguments by noting whether this
pointer changes while analyzing their arguments. Furthermore, if it does,
it provides a suitable error cursor location for the complaint. (This
means that if there's more than one SRF in the arguments, the error will
point at the last one to be analyzed not the first. While connoisseurs of
parsing behavior might find that odd, it's unlikely the average user would
ever notice.)
While at it, we can also provide more specific error messages than before
about some pre-existing restrictions, such as no-SRFs-within-aggregates.
Also, reject at parse time cases where a NULLIF or IS DISTINCT FROM
construct would need to return a set. We've never supported that, but the
restriction is depended on in more subtle ways now, so it seems wise to
detect it at the start.
Also, provide some documentation about how to rewrite a SRF-within-CASE
query using a custom wrapper SRF.
It turns out that the information_schema.user_mapping_options view
contained an instance of exactly the behavior we're now forbidding; but
rewriting it makes it more clear and safer too.
initdb forced because of user_mapping_options change.
Patch by me, with error message suggestions from Alvaro Herrera and
Andres Freund, pursuant to a complaint from Regina Obe.
Discussion: https://postgr.es/m/000001d2d5de$d8d66170$8a832450$@pcorp.us
2017-06-14 05:46:39 +02:00
|
|
|
pstate->p_last_srf,
|
Support ordered-set (WITHIN GROUP) aggregates.
This patch introduces generic support for ordered-set and hypothetical-set
aggregate functions, as well as implementations of the instances defined in
SQL:2008 (percentile_cont(), percentile_disc(), rank(), dense_rank(),
percent_rank(), cume_dist()). We also added mode() though it is not in the
spec, as well as versions of percentile_cont() and percentile_disc() that
can compute multiple percentile values in one pass over the data.
Unlike the original submission, this patch puts full control of the sorting
process in the hands of the aggregate's support functions. To allow the
support functions to find out how they're supposed to sort, a new API
function AggGetAggref() is added to nodeAgg.c. This allows retrieval of
the aggregate call's Aggref node, which may have other uses beyond the
immediate need. There is also support for ordered-set aggregates to
install cleanup callback functions, so that they can be sure that
infrastructure such as tuplesort objects gets cleaned up.
In passing, make some fixes in the recently-added support for variadic
aggregates, and make some editorial adjustments in the recent FILTER
additions for aggregates. Also, simplify use of IsBinaryCoercible() by
allowing it to succeed whenever the target type is ANY or ANYELEMENT.
It was inconsistent that it dealt with other polymorphic target types
but not these.
Atri Sharma and Andrew Gierth; reviewed by Pavel Stehule and Vik Fearing,
and rather heavily editorialized upon by Tom Lane
2013-12-23 22:11:35 +01:00
|
|
|
NULL,
|
2017-11-30 14:46:13 +01:00
|
|
|
false,
|
Support ordered-set (WITHIN GROUP) aggregates.
This patch introduces generic support for ordered-set and hypothetical-set
aggregate functions, as well as implementations of the instances defined in
SQL:2008 (percentile_cont(), percentile_disc(), rank(), dense_rank(),
percent_rank(), cume_dist()). We also added mode() though it is not in the
spec, as well as versions of percentile_cont() and percentile_disc() that
can compute multiple percentile values in one pass over the data.
Unlike the original submission, this patch puts full control of the sorting
process in the hands of the aggregate's support functions. To allow the
support functions to find out how they're supposed to sort, a new API
function AggGetAggref() is added to nodeAgg.c. This allows retrieval of
the aggregate call's Aggref node, which may have other uses beyond the
immediate need. There is also support for ordered-set aggregates to
install cleanup callback functions, so that they can be sure that
infrastructure such as tuplesort objects gets cleaned up.
In passing, make some fixes in the recently-added support for variadic
aggregates, and make some editorial adjustments in the recent FILTER
additions for aggregates. Also, simplify use of IsBinaryCoercible() by
allowing it to succeed whenever the target type is ANY or ANYELEMENT.
It was inconsistent that it dealt with other polymorphic target types
but not these.
Atri Sharma and Andrew Gierth; reviewed by Pavel Stehule and Vik Fearing,
and rather heavily editorialized upon by Tom Lane
2013-12-23 22:11:35 +01:00
|
|
|
cref->location);
|
2012-02-05 01:23:49 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return param;
|
|
|
|
}
|
|
|
|
|
2011-03-25 01:30:14 +01:00
|
|
|
/*
|
|
|
|
* sql_fn_param_ref parser callback for ParamRefs ($n symbols)
|
|
|
|
*/
|
|
|
|
static Node *
|
|
|
|
sql_fn_param_ref(ParseState *pstate, ParamRef *pref)
|
|
|
|
{
|
|
|
|
SQLFunctionParseInfoPtr pinfo = (SQLFunctionParseInfoPtr) pstate->p_ref_hook_state;
|
|
|
|
int paramno = pref->number;
|
|
|
|
|
|
|
|
/* Check parameter number is valid */
|
|
|
|
if (paramno <= 0 || paramno > pinfo->nargs)
|
|
|
|
return NULL; /* unknown parameter number */
|
|
|
|
|
2012-02-05 01:23:49 +01:00
|
|
|
return sql_fn_make_param(pinfo, paramno, pref->location);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sql_fn_make_param construct a Param node for the given paramno
|
|
|
|
*/
|
|
|
|
static Node *
|
|
|
|
sql_fn_make_param(SQLFunctionParseInfoPtr pinfo,
|
|
|
|
int paramno, int location)
|
|
|
|
{
|
|
|
|
Param *param;
|
|
|
|
|
2011-03-25 01:30:14 +01:00
|
|
|
param = makeNode(Param);
|
|
|
|
param->paramkind = PARAM_EXTERN;
|
|
|
|
param->paramid = paramno;
|
|
|
|
param->paramtype = pinfo->argtypes[paramno - 1];
|
|
|
|
param->paramtypmod = -1;
|
|
|
|
param->paramcollid = get_typcollation(param->paramtype);
|
2012-02-05 01:23:49 +01:00
|
|
|
param->location = location;
|
2011-03-25 01:30:14 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we have a function input collation, allow it to override the
|
|
|
|
* type-derived collation for parameter symbols. (XXX perhaps this should
|
|
|
|
* not happen if the type collation is not default?)
|
|
|
|
*/
|
|
|
|
if (OidIsValid(pinfo->collation) && OidIsValid(param->paramcollid))
|
|
|
|
param->paramcollid = pinfo->collation;
|
|
|
|
|
|
|
|
return (Node *) param;
|
|
|
|
}
|
|
|
|
|
2012-02-05 01:23:49 +01:00
|
|
|
/*
|
|
|
|
* Search for a function parameter of the given name; if there is one,
|
|
|
|
* construct and return a Param node for it. If not, return NULL.
|
|
|
|
* Helper function for sql_fn_post_column_ref.
|
|
|
|
*/
|
|
|
|
static Node *
|
|
|
|
sql_fn_resolve_param_name(SQLFunctionParseInfoPtr pinfo,
|
|
|
|
const char *paramname, int location)
|
|
|
|
{
|
2012-06-10 21:20:04 +02:00
|
|
|
int i;
|
2012-02-05 01:23:49 +01:00
|
|
|
|
|
|
|
if (pinfo->argnames == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
for (i = 0; i < pinfo->nargs; i++)
|
|
|
|
{
|
|
|
|
if (pinfo->argnames[i] && strcmp(pinfo->argnames[i], paramname) == 0)
|
|
|
|
return sql_fn_make_param(pinfo, i + 1, location);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
/*
|
|
|
|
* Set up the per-query execution_state records for a SQL function.
|
|
|
|
*
|
|
|
|
* The input is a List of Lists of parsed and rewritten, but not planned,
|
2014-05-06 18:12:18 +02:00
|
|
|
* querytrees. The sublist structure denotes the original query boundaries.
|
2011-03-01 05:27:18 +01:00
|
|
|
*/
|
|
|
|
static List *
|
2008-10-31 20:37:56 +01:00
|
|
|
init_execution_state(List *queryTree_list,
|
|
|
|
SQLFunctionCachePtr fcache,
|
|
|
|
bool lazyEvalOK)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2011-03-01 05:27:18 +01:00
|
|
|
List *eslist = NIL;
|
2008-10-31 20:37:56 +01:00
|
|
|
execution_state *lasttages = NULL;
|
2011-03-01 05:27:18 +01:00
|
|
|
ListCell *lc1;
|
2002-08-23 18:41:38 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
foreach(lc1, queryTree_list)
|
1997-09-07 07:04:48 +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
|
|
|
List *qtlist = lfirst_node(List, lc1);
|
2011-03-01 05:27:18 +01:00
|
|
|
execution_state *firstes = NULL;
|
|
|
|
execution_state *preves = NULL;
|
|
|
|
ListCell *lc2;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
foreach(lc2, qtlist)
|
|
|
|
{
|
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 *queryTree = lfirst_node(Query, lc2);
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
PlannedStmt *stmt;
|
2011-03-01 05:27:18 +01:00
|
|
|
execution_state *newes;
|
2007-02-20 18:32:18 +01:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
/* Plan the query if needed */
|
|
|
|
if (queryTree->commandType == CMD_UTILITY)
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
{
|
|
|
|
/* Utility commands require no planning. */
|
|
|
|
stmt = makeNode(PlannedStmt);
|
|
|
|
stmt->commandType = CMD_UTILITY;
|
|
|
|
stmt->canSetTag = queryTree->canSetTag;
|
|
|
|
stmt->utilityStmt = queryTree->utilityStmt;
|
|
|
|
stmt->stmt_location = queryTree->stmt_location;
|
|
|
|
stmt->stmt_len = queryTree->stmt_len;
|
|
|
|
}
|
2011-03-01 05:27:18 +01:00
|
|
|
else
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
stmt = pg_plan_query(queryTree,
|
2020-03-30 06:51:05 +02:00
|
|
|
fcache->src,
|
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
|
|
|
CURSOR_OPT_PARALLEL_OK,
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
NULL);
|
2011-03-01 05:27:18 +01:00
|
|
|
|
2017-01-14 19:27:47 +01:00
|
|
|
/*
|
|
|
|
* Precheck all commands for validity in a function. This should
|
|
|
|
* generally match the restrictions spi.c applies.
|
|
|
|
*/
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
if (stmt->commandType == CMD_UTILITY)
|
|
|
|
{
|
|
|
|
if (IsA(stmt->utilityStmt, CopyStmt) &&
|
|
|
|
((CopyStmt *) stmt->utilityStmt)->filename == NULL)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
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("cannot COPY to/from client in a SQL function")));
|
2017-01-14 19:27:47 +01:00
|
|
|
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
if (IsA(stmt->utilityStmt, TransactionStmt))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
/* translator: %s is a SQL statement name */
|
|
|
|
errmsg("%s is not allowed in a SQL function",
|
2020-03-02 22:19:51 +01:00
|
|
|
CreateCommandName(stmt->utilityStmt))));
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
}
|
2011-03-01 05:27:18 +01:00
|
|
|
|
|
|
|
if (fcache->readonly_func && !CommandIsReadOnly(stmt))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
/* translator: %s is a SQL statement 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
|
|
|
errmsg("%s is not allowed in a non-volatile function",
|
2020-03-02 22:19:51 +01:00
|
|
|
CreateCommandName((Node *) stmt))));
|
2011-03-01 05:27:18 +01:00
|
|
|
|
|
|
|
/* OK, build the execution_state for this query */
|
|
|
|
newes = (execution_state *) palloc(sizeof(execution_state));
|
|
|
|
if (preves)
|
|
|
|
preves->next = newes;
|
|
|
|
else
|
|
|
|
firstes = newes;
|
2000-04-04 23:44:40 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
newes->next = NULL;
|
|
|
|
newes->status = F_EXEC_START;
|
2011-04-10 17:42:00 +02:00
|
|
|
newes->setsResult = false; /* might change below */
|
|
|
|
newes->lazyEval = false; /* might change below */
|
2011-03-01 05:27:18 +01:00
|
|
|
newes->stmt = stmt;
|
|
|
|
newes->qd = NULL;
|
2002-02-27 20:36:13 +01:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
if (queryTree->canSetTag)
|
|
|
|
lasttages = newes;
|
2002-08-23 18:41:38 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
preves = newes;
|
|
|
|
}
|
2008-10-31 20:37:56 +01:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
eslist = lappend(eslist, firstes);
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Mark the last canSetTag query as delivering the function result; then,
|
|
|
|
* if it is a plain SELECT, mark it for lazy evaluation. If it's not a
|
|
|
|
* SELECT we must always run it to completion.
|
2008-10-31 20:37:56 +01:00
|
|
|
*
|
|
|
|
* Note: at some point we might add additional criteria for whether to use
|
|
|
|
* lazy eval. However, we should prefer to use it whenever the function
|
|
|
|
* doesn't return set, since fetching more than one row is useless in that
|
|
|
|
* case.
|
|
|
|
*
|
|
|
|
* Note: don't set setsResult if the function returns VOID, as evidenced
|
|
|
|
* by not having made a junkfilter. This ensures we'll throw away any
|
2018-03-02 14:57:38 +01:00
|
|
|
* output from the last statement in such a function.
|
2008-10-31 20:37:56 +01:00
|
|
|
*/
|
|
|
|
if (lasttages && fcache->junkFilter)
|
|
|
|
{
|
|
|
|
lasttages->setsResult = true;
|
|
|
|
if (lazyEvalOK &&
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
lasttages->stmt->commandType == CMD_SELECT &&
|
|
|
|
!lasttages->stmt->hasModifyingCTE)
|
|
|
|
fcache->lazyEval = lasttages->lazyEval = true;
|
2008-10-31 20:37:56 +01:00
|
|
|
}
|
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
return eslist;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2011-03-25 01:30:14 +01:00
|
|
|
/*
|
|
|
|
* Initialize the SQLFunctionCache for a SQL function
|
|
|
|
*/
|
2000-08-24 05:29:15 +02:00
|
|
|
static void
|
2020-01-08 17:07:53 +01:00
|
|
|
init_sql_fcache(FunctionCallInfo fcinfo, Oid collation, bool lazyEvalOK)
|
2000-08-24 05:29:15 +02:00
|
|
|
{
|
2020-01-08 17:07:53 +01:00
|
|
|
FmgrInfo *finfo = fcinfo->flinfo;
|
2000-08-24 05:29:15 +02:00
|
|
|
Oid foid = finfo->fn_oid;
|
2013-03-03 23:39:58 +01:00
|
|
|
MemoryContext fcontext;
|
|
|
|
MemoryContext oldcontext;
|
2003-07-01 02:04:39 +02:00
|
|
|
Oid rettype;
|
2020-01-08 17:07:53 +01:00
|
|
|
TupleDesc rettupdesc;
|
2000-08-24 05:29:15 +02:00
|
|
|
HeapTuple procedureTuple;
|
|
|
|
Form_pg_proc procedureStruct;
|
|
|
|
SQLFunctionCachePtr fcache;
|
2011-03-01 05:27:18 +01:00
|
|
|
List *raw_parsetree_list;
|
2004-04-03 01:14:08 +02:00
|
|
|
List *queryTree_list;
|
2011-03-01 05:27:18 +01:00
|
|
|
List *flat_query_list;
|
2020-01-08 17:07:53 +01:00
|
|
|
List *resulttlist;
|
2011-03-01 05:27:18 +01:00
|
|
|
ListCell *lc;
|
2000-08-24 05:29:15 +02:00
|
|
|
Datum tmp;
|
|
|
|
bool isNull;
|
|
|
|
|
2013-03-03 23:39:58 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Create memory context that holds all the SQLFunctionCache data. It
|
2013-03-03 23:39:58 +01:00
|
|
|
* must be a child of whatever context holds the FmgrInfo.
|
|
|
|
*/
|
|
|
|
fcontext = AllocSetContextCreate(finfo->fn_mcxt,
|
Allow memory contexts to have both fixed and variable ident strings.
Originally, we treated memory context names as potentially variable in
all cases, and therefore always copied them into the context header.
Commit 9fa6f00b1 rethought this a little bit and invented a distinction
between fixed and variable names, skipping the copy step for the former.
But we can make things both simpler and more useful by instead allowing
there to be two parts to a context's identification, a fixed "name" and
an optional, variable "ident". The name supplied in the context create
call is now required to be a compile-time-constant string in all cases,
as it is never copied but just pointed to. The "ident" string, if
wanted, is supplied later. This is needed because typically we want
the ident to be stored inside the context so that it's cleaned up
automatically on context deletion; that means it has to be copied into
the context before we can set the pointer.
The cost of this approach is basically just an additional pointer field
in struct MemoryContextData, which isn't much overhead, and is bought
back entirely in the AllocSet case by not needing a headerSize field
anymore, since we no longer have to cope with variable header length.
In addition, we can simplify the internal interfaces for memory context
creation still further, saving a few cycles there. And it's no longer
true that a custom identifier disqualifies a context from participating
in aset.c's freelist scheme, so possibly there's some win on that end.
All the places that were using non-compile-time-constant context names
are adjusted to put the variable info into the "ident" instead. This
allows more effective identification of those contexts in many cases;
for example, subsidary contexts of relcache entries are now identified
by both type (e.g. "index info") and relname, where before you got only
one or the other. Contexts associated with PL function cache entries
are now identified more fully and uniformly, too.
I also arranged for plancache contexts to use the query source string
as their identifier. This is basically free for CachedPlanSources, as
they contained a copy of that string already. We pay an extra pstrdup
to do it for CachedPlans. That could perhaps be avoided, but it would
make things more fragile (since the CachedPlanSource is sometimes
destroyed first). I suspect future improvements in error reporting will
require CachedPlans to have a copy of that string anyway, so it's not
clear that it's worth moving mountains to avoid it now.
This also changes the APIs for context statistics routines so that the
context-specific routines no longer assume that output goes straight
to stderr, nor do they know all details of the output format. This
is useful immediately to reduce code duplication, and it also allows
for external code to do something with stats output that's different
from printing to stderr.
The reason for pushing this now rather than waiting for v12 is that
it rethinks some of the API changes made by commit 9fa6f00b1. Seems
better for extension authors to endure just one round of API changes
not two.
Discussion: https://postgr.es/m/CAB=Je-FdtmFZ9y9REHD7VsSrnCkiBhsA4mdsLKSPauwXtQBeNA@mail.gmail.com
2018-03-27 22:46:47 +02:00
|
|
|
"SQL function",
|
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);
|
2013-03-03 23:39:58 +01:00
|
|
|
|
|
|
|
oldcontext = MemoryContextSwitchTo(fcontext);
|
|
|
|
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Create the struct proper, link it to fcontext and fn_extra. Once this
|
2013-03-03 23:39:58 +01:00
|
|
|
* is done, we'll be able to recover the memory after failure, even if the
|
|
|
|
* FmgrInfo is long-lived.
|
|
|
|
*/
|
2003-07-01 02:04:39 +02:00
|
|
|
fcache = (SQLFunctionCachePtr) palloc0(sizeof(SQLFunctionCache));
|
2013-03-03 23:39:58 +01:00
|
|
|
fcache->fcontext = fcontext;
|
2010-03-19 23:54:41 +01:00
|
|
|
finfo->fn_extra = (void *) fcache;
|
2003-07-01 02:04:39 +02:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
|
|
|
* get the procedure tuple corresponding to the given function Oid
|
2000-08-24 05:29:15 +02:00
|
|
|
*/
|
2010-02-14 19:42:19 +01:00
|
|
|
procedureTuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(foid));
|
2000-08-24 05:29:15 +02:00
|
|
|
if (!HeapTupleIsValid(procedureTuple))
|
2003-07-21 19:05:12 +02:00
|
|
|
elog(ERROR, "cache lookup failed for function %u", foid);
|
2000-08-24 05:29:15 +02:00
|
|
|
procedureStruct = (Form_pg_proc) GETSTRUCT(procedureTuple);
|
|
|
|
|
2010-03-19 23:54:41 +01:00
|
|
|
/*
|
Allow memory contexts to have both fixed and variable ident strings.
Originally, we treated memory context names as potentially variable in
all cases, and therefore always copied them into the context header.
Commit 9fa6f00b1 rethought this a little bit and invented a distinction
between fixed and variable names, skipping the copy step for the former.
But we can make things both simpler and more useful by instead allowing
there to be two parts to a context's identification, a fixed "name" and
an optional, variable "ident". The name supplied in the context create
call is now required to be a compile-time-constant string in all cases,
as it is never copied but just pointed to. The "ident" string, if
wanted, is supplied later. This is needed because typically we want
the ident to be stored inside the context so that it's cleaned up
automatically on context deletion; that means it has to be copied into
the context before we can set the pointer.
The cost of this approach is basically just an additional pointer field
in struct MemoryContextData, which isn't much overhead, and is bought
back entirely in the AllocSet case by not needing a headerSize field
anymore, since we no longer have to cope with variable header length.
In addition, we can simplify the internal interfaces for memory context
creation still further, saving a few cycles there. And it's no longer
true that a custom identifier disqualifies a context from participating
in aset.c's freelist scheme, so possibly there's some win on that end.
All the places that were using non-compile-time-constant context names
are adjusted to put the variable info into the "ident" instead. This
allows more effective identification of those contexts in many cases;
for example, subsidary contexts of relcache entries are now identified
by both type (e.g. "index info") and relname, where before you got only
one or the other. Contexts associated with PL function cache entries
are now identified more fully and uniformly, too.
I also arranged for plancache contexts to use the query source string
as their identifier. This is basically free for CachedPlanSources, as
they contained a copy of that string already. We pay an extra pstrdup
to do it for CachedPlans. That could perhaps be avoided, but it would
make things more fragile (since the CachedPlanSource is sometimes
destroyed first). I suspect future improvements in error reporting will
require CachedPlans to have a copy of that string anyway, so it's not
clear that it's worth moving mountains to avoid it now.
This also changes the APIs for context statistics routines so that the
context-specific routines no longer assume that output goes straight
to stderr, nor do they know all details of the output format. This
is useful immediately to reduce code duplication, and it also allows
for external code to do something with stats output that's different
from printing to stderr.
The reason for pushing this now rather than waiting for v12 is that
it rethinks some of the API changes made by commit 9fa6f00b1. Seems
better for extension authors to endure just one round of API changes
not two.
Discussion: https://postgr.es/m/CAB=Je-FdtmFZ9y9REHD7VsSrnCkiBhsA4mdsLKSPauwXtQBeNA@mail.gmail.com
2018-03-27 22:46:47 +02:00
|
|
|
* copy function name immediately for use by error reporting callback, and
|
|
|
|
* for use as memory context identifier
|
2010-03-19 23:54:41 +01:00
|
|
|
*/
|
|
|
|
fcache->fname = pstrdup(NameStr(procedureStruct->proname));
|
Allow memory contexts to have both fixed and variable ident strings.
Originally, we treated memory context names as potentially variable in
all cases, and therefore always copied them into the context header.
Commit 9fa6f00b1 rethought this a little bit and invented a distinction
between fixed and variable names, skipping the copy step for the former.
But we can make things both simpler and more useful by instead allowing
there to be two parts to a context's identification, a fixed "name" and
an optional, variable "ident". The name supplied in the context create
call is now required to be a compile-time-constant string in all cases,
as it is never copied but just pointed to. The "ident" string, if
wanted, is supplied later. This is needed because typically we want
the ident to be stored inside the context so that it's cleaned up
automatically on context deletion; that means it has to be copied into
the context before we can set the pointer.
The cost of this approach is basically just an additional pointer field
in struct MemoryContextData, which isn't much overhead, and is bought
back entirely in the AllocSet case by not needing a headerSize field
anymore, since we no longer have to cope with variable header length.
In addition, we can simplify the internal interfaces for memory context
creation still further, saving a few cycles there. And it's no longer
true that a custom identifier disqualifies a context from participating
in aset.c's freelist scheme, so possibly there's some win on that end.
All the places that were using non-compile-time-constant context names
are adjusted to put the variable info into the "ident" instead. This
allows more effective identification of those contexts in many cases;
for example, subsidary contexts of relcache entries are now identified
by both type (e.g. "index info") and relname, where before you got only
one or the other. Contexts associated with PL function cache entries
are now identified more fully and uniformly, too.
I also arranged for plancache contexts to use the query source string
as their identifier. This is basically free for CachedPlanSources, as
they contained a copy of that string already. We pay an extra pstrdup
to do it for CachedPlans. That could perhaps be avoided, but it would
make things more fragile (since the CachedPlanSource is sometimes
destroyed first). I suspect future improvements in error reporting will
require CachedPlans to have a copy of that string anyway, so it's not
clear that it's worth moving mountains to avoid it now.
This also changes the APIs for context statistics routines so that the
context-specific routines no longer assume that output goes straight
to stderr, nor do they know all details of the output format. This
is useful immediately to reduce code duplication, and it also allows
for external code to do something with stats output that's different
from printing to stderr.
The reason for pushing this now rather than waiting for v12 is that
it rethinks some of the API changes made by commit 9fa6f00b1. Seems
better for extension authors to endure just one round of API changes
not two.
Discussion: https://postgr.es/m/CAB=Je-FdtmFZ9y9REHD7VsSrnCkiBhsA4mdsLKSPauwXtQBeNA@mail.gmail.com
2018-03-27 22:46:47 +02:00
|
|
|
MemoryContextSetIdentifier(fcontext, fcache->fname);
|
2010-03-19 23:54:41 +01:00
|
|
|
|
2001-03-22 07:16:21 +01:00
|
|
|
/*
|
2020-01-08 17:07:53 +01:00
|
|
|
* Resolve any polymorphism, obtaining the actual result type, and the
|
|
|
|
* corresponding tupdesc if it's a rowtype.
|
2000-08-24 05:29:15 +02:00
|
|
|
*/
|
2020-01-08 17:07:53 +01:00
|
|
|
(void) get_call_result_type(fcinfo, &rettype, &rettupdesc);
|
2003-07-01 02:04:39 +02:00
|
|
|
|
2004-07-15 15:51:38 +02:00
|
|
|
fcache->rettype = rettype;
|
|
|
|
|
2007-02-02 01:02:55 +01:00
|
|
|
/* Fetch the typlen and byval info for the result type */
|
2018-03-02 14:57:38 +01:00
|
|
|
get_typlenbyval(rettype, &fcache->typlen, &fcache->typbyval);
|
2007-02-02 01:02:55 +01:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Remember whether we're returning setof something */
|
|
|
|
fcache->returnsSet = procedureStruct->proretset;
|
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
/* Remember if function is STABLE/IMMUTABLE */
|
|
|
|
fcache->readonly_func =
|
|
|
|
(procedureStruct->provolatile != PROVOLATILE_VOLATILE);
|
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
/*
|
2011-03-25 01:30:14 +01:00
|
|
|
* We need the actual argument types to pass to the parser. Also make
|
|
|
|
* sure that parameter symbols are considered to have the function's
|
|
|
|
* resolved input collation.
|
2002-12-05 16:50:39 +01:00
|
|
|
*/
|
2011-03-25 01:30:14 +01:00
|
|
|
fcache->pinfo = prepare_sql_fn_parse_info(procedureTuple,
|
|
|
|
finfo->fn_expr,
|
2011-04-13 01:19:24 +02:00
|
|
|
collation);
|
2000-08-24 05:29:15 +02:00
|
|
|
|
2007-02-02 01:02:55 +01:00
|
|
|
/*
|
2007-03-13 01:33:44 +01:00
|
|
|
* And of course we need the function body text.
|
2007-02-02 01:02:55 +01:00
|
|
|
*/
|
2000-08-24 05:29:15 +02:00
|
|
|
tmp = SysCacheGetAttr(PROCOID,
|
|
|
|
procedureTuple,
|
|
|
|
Anum_pg_proc_prosrc,
|
|
|
|
&isNull);
|
|
|
|
if (isNull)
|
2003-07-21 19:05:12 +02:00
|
|
|
elog(ERROR, "null prosrc for function %u", foid);
|
2008-03-25 23:42:46 +01:00
|
|
|
fcache->src = TextDatumGetCString(tmp);
|
2000-08-24 05:29:15 +02:00
|
|
|
|
2007-03-13 01:33:44 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* Parse and rewrite the queries in the function text. Use sublists to
|
2011-03-01 05:27:18 +01:00
|
|
|
* keep track of the original query boundaries. But we also build a
|
|
|
|
* "flat" list of the rewritten queries to pass to check_sql_fn_retval.
|
|
|
|
* This is because the last canSetTag query determines the result type
|
|
|
|
* independently of query boundaries --- and it might not be in the last
|
|
|
|
* sublist, for example if the last query rewrites to DO INSTEAD NOTHING.
|
|
|
|
* (It might not be unreasonable to throw an error in such a case, but
|
|
|
|
* this is the historical behavior and it doesn't seem worth changing.)
|
2013-03-03 23:39:58 +01:00
|
|
|
*
|
|
|
|
* Note: since parsing and planning is done in fcontext, we will generate
|
|
|
|
* a lot of cruft that lives as long as the fcache does. This is annoying
|
|
|
|
* but we'll not worry about it until the module is rewritten to use
|
|
|
|
* plancache.c.
|
2007-03-13 01:33:44 +01:00
|
|
|
*/
|
2011-03-01 05:27:18 +01:00
|
|
|
raw_parsetree_list = pg_parse_query(fcache->src);
|
|
|
|
|
|
|
|
queryTree_list = NIL;
|
|
|
|
flat_query_list = NIL;
|
|
|
|
foreach(lc, raw_parsetree_list)
|
|
|
|
{
|
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
|
|
|
RawStmt *parsetree = lfirst_node(RawStmt, lc);
|
2011-03-01 05:27:18 +01:00
|
|
|
List *queryTree_sublist;
|
|
|
|
|
2011-03-25 01:30:14 +01:00
|
|
|
queryTree_sublist = pg_analyze_and_rewrite_params(parsetree,
|
|
|
|
fcache->src,
|
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
|
|
|
(ParserSetupHook) sql_fn_parser_setup,
|
2017-04-01 06:17:18 +02:00
|
|
|
fcache->pinfo,
|
|
|
|
NULL);
|
2011-03-01 05:27:18 +01:00
|
|
|
queryTree_list = lappend(queryTree_list, queryTree_sublist);
|
Rationalize use of list_concat + list_copy combinations.
In the wake of commit 1cff1b95a, the result of list_concat no longer
shares the ListCells of the second input. Therefore, we can replace
"list_concat(x, list_copy(y))" with just "list_concat(x, y)".
To improve call sites that were list_copy'ing the first argument,
or both arguments, invent "list_concat_copy()" which produces a new
list sharing no ListCells with either input. (This is a bit faster
than "list_concat(list_copy(x), y)" because it makes the result list
the right size to start with.)
In call sites that were not list_copy'ing the second argument, the new
semantics mean that we are usually leaking the second List's storage,
since typically there is no remaining pointer to it. We considered
inventing another list_copy variant that would list_free the second
input, but concluded that for most call sites it isn't worth worrying
about, given the relative compactness of the new List representation.
(Note that in cases where such leakage would happen, the old code
already leaked the second List's header; so we're only discussing
the size of the leak not whether there is one. I did adjust two or
three places that had been troubling to free that header so that
they manually free the whole second List.)
Patch by me; thanks to David Rowley for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-08-12 17:20:18 +02:00
|
|
|
flat_query_list = list_concat(flat_query_list, queryTree_sublist);
|
2011-03-01 05:27:18 +01:00
|
|
|
}
|
2004-04-03 01:14:08 +02:00
|
|
|
|
2018-03-14 16:47:21 +01:00
|
|
|
check_sql_fn_statements(flat_query_list);
|
|
|
|
|
2004-04-03 01:14:08 +02:00
|
|
|
/*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Check that the function returns the type it claims to. Although in
|
|
|
|
* simple cases this was already done when the function was defined, we
|
|
|
|
* have to recheck because database objects used in the function's queries
|
2020-01-08 17:07:53 +01:00
|
|
|
* might have changed type. We'd have to recheck anyway if the function
|
|
|
|
* had any polymorphic arguments. Moreover, check_sql_fn_retval takes
|
|
|
|
* care of injecting any required column type coercions. (But we don't
|
|
|
|
* ask it to insert nulls for dropped columns; the junkfilter handles
|
|
|
|
* that.)
|
2004-04-03 01:14:08 +02:00
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Note: we set fcache->returnsTuple according to whether we are returning
|
2014-05-06 18:12:18 +02:00
|
|
|
* the whole tuple result or just a single column. In the latter case we
|
2007-11-15 22:14:46 +01:00
|
|
|
* clear returnsTuple because we need not act different from the scalar
|
2009-06-11 16:49:15 +02:00
|
|
|
* result case, even if it's a rowtype column. (However, we have to force
|
|
|
|
* lazy eval mode in that case; otherwise we'd need extra code to expand
|
|
|
|
* the rowtype column into multiple columns, since we have no way to
|
|
|
|
* notify the caller that it should do that.)
|
2004-04-03 01:14:08 +02:00
|
|
|
*/
|
2020-01-08 17:07:53 +01:00
|
|
|
fcache->returnsTuple = check_sql_fn_retval(flat_query_list,
|
2007-02-02 01:02:55 +01:00
|
|
|
rettype,
|
2020-01-08 17:07:53 +01:00
|
|
|
rettupdesc,
|
|
|
|
false,
|
|
|
|
&resulttlist);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Construct a JunkFilter we can use to coerce the returned rowtype to the
|
|
|
|
* desired form, unless the result type is VOID, in which case there's
|
|
|
|
* nothing to coerce to. (XXX Frequently, the JunkFilter isn't doing
|
|
|
|
* anything very interesting, but much of this module expects it to be
|
|
|
|
* there anyway.)
|
|
|
|
*/
|
|
|
|
if (rettype != VOIDOID)
|
|
|
|
{
|
|
|
|
TupleTableSlot *slot = MakeSingleTupleTableSlot(NULL,
|
|
|
|
&TTSOpsMinimalTuple);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the result is composite, *and* we are returning the whole tuple
|
|
|
|
* result, we need to insert nulls for any dropped columns. In the
|
|
|
|
* single-column-result case, there might be dropped columns within
|
|
|
|
* the composite column value, but it's not our problem here. There
|
|
|
|
* should be no resjunk entries in resulttlist, so in the second case
|
|
|
|
* the JunkFilter is certainly a no-op.
|
|
|
|
*/
|
|
|
|
if (rettupdesc && fcache->returnsTuple)
|
|
|
|
fcache->junkFilter = ExecInitJunkFilterConversion(resulttlist,
|
|
|
|
rettupdesc,
|
|
|
|
slot);
|
|
|
|
else
|
|
|
|
fcache->junkFilter = ExecInitJunkFilter(resulttlist, slot);
|
|
|
|
}
|
2004-04-03 01:14:08 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
if (fcache->returnsTuple)
|
|
|
|
{
|
|
|
|
/* Make sure output rowtype is properly blessed */
|
|
|
|
BlessTupleDesc(fcache->junkFilter->jf_resultSlot->tts_tupleDescriptor);
|
|
|
|
}
|
|
|
|
else if (fcache->returnsSet && type_is_rowtype(fcache->rettype))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Returning rowtype as if it were scalar --- materialize won't work.
|
|
|
|
* Right now it's sufficient to override any caller preference for
|
|
|
|
* materialize mode, but to add more smarts in init_execution_state
|
|
|
|
* about this, we'd probably need a three-way flag instead of bool.
|
|
|
|
*/
|
|
|
|
lazyEvalOK = true;
|
|
|
|
}
|
|
|
|
|
2004-04-03 01:14:08 +02:00
|
|
|
/* Finally, plan the queries */
|
2004-09-13 22:10:13 +02:00
|
|
|
fcache->func_state = init_execution_state(queryTree_list,
|
2008-10-31 20:37:56 +01:00
|
|
|
fcache,
|
|
|
|
lazyEvalOK);
|
2000-08-24 05:29:15 +02:00
|
|
|
|
2013-03-03 23:39:58 +01:00
|
|
|
/* Mark fcache with time of creation to show it's valid */
|
|
|
|
fcache->lxid = MyProc->lxid;
|
|
|
|
fcache->subxid = GetCurrentSubTransactionId();
|
|
|
|
|
2000-11-16 23:30:52 +01:00
|
|
|
ReleaseSysCache(procedureTuple);
|
2013-03-03 23:39:58 +01:00
|
|
|
|
|
|
|
MemoryContextSwitchTo(oldcontext);
|
2000-08-24 05:29:15 +02:00
|
|
|
}
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Start up execution of one execution_state node */
|
2001-01-29 01:39:20 +01:00
|
|
|
static void
|
2002-12-05 16:50:39 +01:00
|
|
|
postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
DestReceiver *dest;
|
2004-09-13 22:10:13 +02:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
Assert(es->qd == NULL);
|
2004-09-13 22:10:13 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
/* Caller should have ensured a suitable snapshot is active */
|
|
|
|
Assert(ActiveSnapshotSet());
|
2004-09-13 22:10:13 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
|
|
|
* If this query produces the function result, send its output to the
|
|
|
|
* tuplestore; else discard any output.
|
|
|
|
*/
|
|
|
|
if (es->setsResult)
|
|
|
|
{
|
|
|
|
DR_sqlfunction *myState;
|
|
|
|
|
2008-11-30 21:51:25 +01:00
|
|
|
dest = CreateDestReceiver(DestSQLFunction);
|
2008-10-31 20:37:56 +01:00
|
|
|
/* pass down the needed info to the dest receiver routines */
|
|
|
|
myState = (DR_sqlfunction *) dest;
|
|
|
|
Assert(myState->pub.mydest == DestSQLFunction);
|
|
|
|
myState->tstore = fcache->tstore;
|
|
|
|
myState->cxt = CurrentMemoryContext;
|
|
|
|
myState->filter = fcache->junkFilter;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
dest = None_Receiver;
|
|
|
|
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
es->qd = CreateQueryDesc(es->stmt,
|
|
|
|
fcache->src,
|
|
|
|
GetActiveSnapshot(),
|
|
|
|
InvalidSnapshot,
|
|
|
|
dest,
|
2017-04-01 06:17:18 +02:00
|
|
|
fcache->paramLI,
|
|
|
|
es->qd ? es->qd->queryEnv : NULL,
|
|
|
|
0);
|
2002-12-05 16:50:39 +01:00
|
|
|
|
|
|
|
/* Utility commands don't need Executor. */
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
if (es->qd->operation != CMD_UTILITY)
|
2004-09-10 20:40:09 +02:00
|
|
|
{
|
2006-10-12 19:02:24 +02:00
|
|
|
/*
|
2011-02-27 19:43:29 +01:00
|
|
|
* In lazyEval mode, do not let the executor set up an AfterTrigger
|
|
|
|
* context. This is necessary not just an optimization, because we
|
|
|
|
* mustn't exit from the function execution with a stacked
|
|
|
|
* AfterTrigger level still active. We are careful not to select
|
|
|
|
* lazyEval mode for any statement that could possibly queue triggers.
|
2006-10-12 19:02:24 +02:00
|
|
|
*/
|
2011-02-27 19:43:29 +01:00
|
|
|
int eflags;
|
|
|
|
|
|
|
|
if (es->lazyEval)
|
|
|
|
eflags = EXEC_FLAG_SKIP_TRIGGERS;
|
|
|
|
else
|
|
|
|
eflags = 0; /* default run-to-completion flags */
|
|
|
|
ExecutorStart(es->qd, eflags);
|
2004-09-10 20:40:09 +02:00
|
|
|
}
|
2002-12-05 16:50:39 +01:00
|
|
|
|
|
|
|
es->status = F_EXEC_RUN;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Run one execution_state; either to completion or to first result row */
|
2008-10-31 22:07:55 +01:00
|
|
|
/* Returns true if we ran to completion */
|
|
|
|
static bool
|
2007-03-13 01:33:44 +01:00
|
|
|
postquel_getnext(execution_state *es, SQLFunctionCachePtr fcache)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2008-10-31 22:07:55 +01:00
|
|
|
bool result;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
if (es->qd->operation == CMD_UTILITY)
|
2008-05-12 22:02:02 +02:00
|
|
|
{
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
ProcessUtility(es->qd->plannedstmt,
|
2008-05-12 22:02:02 +02:00
|
|
|
fcache->src,
|
2013-04-28 06:18:45 +02:00
|
|
|
PROCESS_UTILITY_QUERY,
|
2008-05-12 22:02:02 +02:00
|
|
|
es->qd->params,
|
2017-04-01 06:17:18 +02:00
|
|
|
es->qd->queryEnv,
|
2008-05-12 22:02:02 +02:00
|
|
|
es->qd->dest,
|
2013-04-28 06:18:45 +02:00
|
|
|
NULL);
|
2008-10-31 22:07:55 +01:00
|
|
|
result = true; /* never stops early */
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2008-05-12 22:02:02 +02:00
|
|
|
else
|
2004-09-13 22:10:13 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Run regular commands to completion unless lazyEval */
|
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 count = (es->lazyEval) ? 1 : 0;
|
2008-05-12 22:02:02 +02:00
|
|
|
|
2017-03-23 18:05:48 +01:00
|
|
|
ExecutorRun(es->qd, ForwardScanDirection, count, !fcache->returnsSet || !es->lazyEval);
|
2008-10-31 22:07:55 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If we requested run to completion OR there was no tuple returned,
|
|
|
|
* command must be complete.
|
|
|
|
*/
|
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
|
|
|
result = (count == 0 || es->qd->estate->es_processed == 0);
|
2004-09-13 22:10:13 +02:00
|
|
|
}
|
1996-09-16 07:36:38 +02:00
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
return result;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Shut down execution of one execution_state node */
|
1996-07-09 08:22:35 +02:00
|
|
|
static void
|
2005-04-10 20:04:20 +02:00
|
|
|
postquel_end(execution_state *es)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2003-07-28 20:33:18 +02:00
|
|
|
/* mark status done to ensure we don't do ExecutorEnd twice */
|
|
|
|
es->status = F_EXEC_DONE;
|
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
/* Utility commands don't need Executor. */
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
if (es->qd->operation != CMD_UTILITY)
|
2004-09-10 20:40:09 +02:00
|
|
|
{
|
2011-02-27 19:43:29 +01:00
|
|
|
ExecutorFinish(es->qd);
|
2008-05-12 22:02:02 +02:00
|
|
|
ExecutorEnd(es->qd);
|
2004-09-10 20:40:09 +02:00
|
|
|
}
|
2002-12-05 16:50:39 +01:00
|
|
|
|
2017-09-07 18:06:23 +02:00
|
|
|
es->qd->dest->rDestroy(es->qd->dest);
|
2008-11-27 01:10:04 +01:00
|
|
|
|
2002-12-15 17:17:59 +01:00
|
|
|
FreeQueryDesc(es->qd);
|
2002-12-05 16:50:39 +01:00
|
|
|
es->qd = NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
/* Build ParamListInfo array representing current arguments */
|
1996-07-09 08:22:35 +02:00
|
|
|
static void
|
2002-12-05 16:50:39 +01:00
|
|
|
postquel_sub_params(SQLFunctionCachePtr fcache,
|
|
|
|
FunctionCallInfo fcinfo)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2002-12-05 16:50:39 +01:00
|
|
|
int nargs = fcinfo->nargs;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
if (nargs > 0)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
ParamListInfo paramLI;
|
2002-12-05 16:50:39 +01:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
if (fcache->paramLI == NULL)
|
|
|
|
{
|
2019-03-14 13:30:09 +01:00
|
|
|
paramLI = makeParamList(nargs);
|
2008-10-31 20:37:56 +01:00
|
|
|
fcache->paramLI = paramLI;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
paramLI = fcache->paramLI;
|
|
|
|
Assert(paramLI->numParams == nargs);
|
|
|
|
}
|
2002-12-05 16:50:39 +01:00
|
|
|
|
2019-03-14 13:30:09 +01:00
|
|
|
for (int i = 0; i < nargs; i++)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2006-04-22 03:26:01 +02:00
|
|
|
ParamExternData *prm = ¶mLI->params[i];
|
|
|
|
|
Change function call information to be variable length.
Before this change FunctionCallInfoData, the struct arguments etc for
V1 function calls are stored in, always had space for
FUNC_MAX_ARGS/100 arguments, storing datums and their nullness in two
arrays. For nearly every function call 100 arguments is far more than
needed, therefore wasting memory. Arg and argnull being two separate
arrays also guarantees that to access a single argument, two
cachelines have to be touched.
Change the layout so there's a single variable-length array with pairs
of value / isnull. That drastically reduces memory consumption for
most function calls (on x86-64 a two argument function now uses
64bytes, previously 936 bytes), and makes it very likely that argument
value and its nullness are on the same cacheline.
Arguments are stored in a new NullableDatum struct, which, due to
padding, needs more memory per argument than before. But as usually
far fewer arguments are stored, and individual arguments are cheaper
to access, that's still a clear win. It's likely that there's other
places where conversion to NullableDatum arrays would make sense,
e.g. TupleTableSlots, but that's for another commit.
Because the function call information is now variable-length
allocations have to take the number of arguments into account. For
heap allocations that can be done with SizeForFunctionCallInfoData(),
for on-stack allocations there's a new LOCAL_FCINFO(name, nargs) macro
that helps to allocate an appropriately sized and aligned variable.
Some places with stack allocation function call information don't know
the number of arguments at compile time, and currently variably sized
stack allocations aren't allowed in postgres. Therefore allow for
FUNC_MAX_ARGS space in these cases. They're not that common, so for
now that seems acceptable.
Because of the need to allocate FunctionCallInfo of the appropriate
size, older extensions may need to update their code. To avoid subtle
breakages, the FunctionCallInfoData struct has been renamed to
FunctionCallInfoBaseData. Most code only references FunctionCallInfo,
so that shouldn't cause much collateral damage.
This change is also a prerequisite for more efficient expression JIT
compilation (by allocating the function call information on the stack,
allowing LLVM to optimize it away); previously the size of the call
information caused problems inside LLVM's optimizer.
Author: Andres Freund
Reviewed-By: Tom Lane
Discussion: https://postgr.es/m/20180605172952.x34m5uz6ju6enaem@alap3.anarazel.de
2019-01-26 23:17:52 +01:00
|
|
|
prm->value = fcinfo->args[i].value;
|
|
|
|
prm->isnull = fcinfo->args[i].isnull;
|
2006-09-06 22:40:48 +02:00
|
|
|
prm->pflags = 0;
|
2011-03-25 01:30:14 +01:00
|
|
|
prm->ptype = fcache->pinfo->argtypes[i];
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2002-12-05 16:50:39 +01:00
|
|
|
else
|
2008-10-31 20:37:56 +01:00
|
|
|
fcache->paramLI = NULL;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
|
|
|
* Extract the SQL function's value from a single result row. This is used
|
|
|
|
* both for scalar (non-set) functions and for each row of a lazy-eval set
|
|
|
|
* result.
|
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static Datum
|
2008-10-31 20:37:56 +01:00
|
|
|
postquel_get_single_result(TupleTableSlot *slot,
|
|
|
|
FunctionCallInfo fcinfo,
|
|
|
|
SQLFunctionCachePtr fcache,
|
|
|
|
MemoryContext resultcontext)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1997-09-08 04:41:22 +02:00
|
|
|
Datum value;
|
2005-04-10 20:04:20 +02:00
|
|
|
MemoryContext oldcontext;
|
1997-01-22 06:26:50 +01:00
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Set up to return the function value. For pass-by-reference datatypes,
|
|
|
|
* be sure to allocate the result in resultcontext, not the current memory
|
2014-05-06 18:12:18 +02:00
|
|
|
* context (which has query lifespan). We can't leave the data in the
|
2008-10-31 20:37:56 +01:00
|
|
|
* TupleTableSlot because we intend to clear the slot before returning.
|
2004-09-13 22:10:13 +02:00
|
|
|
*/
|
2005-04-10 20:04:20 +02:00
|
|
|
oldcontext = MemoryContextSwitchTo(resultcontext);
|
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
if (fcache->returnsTuple)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
/* We must return the whole tuple as a Datum. */
|
2004-09-13 22:10:13 +02:00
|
|
|
fcinfo->isnull = false;
|
Rejigger materializing and fetching a HeapTuple from a slot.
Previously materializing a slot always returned a HeapTuple. As
current work aims to reduce the reliance on HeapTuples (so other
storage systems can work efficiently), that needs to change. Thus
split the tasks of materializing a slot (i.e. making it independent
from the underlying storage / other memory contexts) from fetching a
HeapTuple from the slot. For brevity, allow to fetch a HeapTuple from
a slot and materializing the slot at the same time, controlled by a
parameter.
For now some callers of ExecFetchSlotHeapTuple, with materialize =
true, expect that changes to the heap tuple will be reflected in the
underlying slot. Those places will be adapted in due course, so while
not pretty, that's OK for now.
Also rename ExecFetchSlotTuple to ExecFetchSlotHeapTupleDatum and
ExecFetchSlotTupleDatum to ExecFetchSlotHeapTupleDatum, as it's likely
that future storage methods will need similar methods. There already
is ExecFetchSlotMinimalTuple, so the new names make the naming scheme
more coherent.
Author: Ashutosh Bapat and Andres Freund, with changes by Amit Khandekar
Discussion: https://postgr.es/m/20181105210039.hh4vvi4vwoq5ba2q@alap3.anarazel.de
2018-11-15 23:26:14 +01:00
|
|
|
value = ExecFetchSlotHeapTupleDatum(slot);
|
2004-09-13 22:10:13 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Returning a scalar, which we have to extract from the first column
|
|
|
|
* of the SELECT result, and then copy into result context if needed.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-03-16 22:38:10 +01:00
|
|
|
value = slot_getattr(slot, 1, &(fcinfo->isnull));
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
if (!fcinfo->isnull)
|
|
|
|
value = datumCopy(value, fcache->typbyval, fcache->typlen);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2005-04-10 20:04:20 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
2004-09-13 22:10:13 +02:00
|
|
|
return value;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
|
|
|
* fmgr_sql: function call manager for SQL functions
|
|
|
|
*/
|
1996-07-09 08:22:35 +02:00
|
|
|
Datum
|
2000-08-24 05:29:15 +02:00
|
|
|
fmgr_sql(PG_FUNCTION_ARGS)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2000-08-24 05:29:15 +02:00
|
|
|
SQLFunctionCachePtr fcache;
|
2003-07-28 20:33:18 +02:00
|
|
|
ErrorContextCallback sqlerrcontext;
|
2013-03-03 23:39:58 +01:00
|
|
|
MemoryContext oldcontext;
|
2008-10-31 20:37:56 +01:00
|
|
|
bool randomAccess;
|
|
|
|
bool lazyEvalOK;
|
2011-03-01 05:27:18 +01:00
|
|
|
bool is_first;
|
|
|
|
bool pushed_snapshot;
|
1997-09-07 07:04:48 +02:00
|
|
|
execution_state *es;
|
2008-10-31 20:37:56 +01:00
|
|
|
TupleTableSlot *slot;
|
|
|
|
Datum result;
|
2011-04-10 17:42:00 +02:00
|
|
|
List *eslist;
|
|
|
|
ListCell *eslc;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2003-07-28 20:33:18 +02:00
|
|
|
/*
|
|
|
|
* Setup error traceback support for ereport()
|
|
|
|
*/
|
|
|
|
sqlerrcontext.callback = sql_exec_error_callback;
|
|
|
|
sqlerrcontext.arg = fcinfo->flinfo;
|
|
|
|
sqlerrcontext.previous = error_context_stack;
|
|
|
|
error_context_stack = &sqlerrcontext;
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Check call context */
|
|
|
|
if (fcinfo->flinfo->fn_retset)
|
|
|
|
{
|
|
|
|
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* For simplicity, we require callers to support both set eval modes.
|
|
|
|
* There are cases where we must use one or must use the other, and
|
2010-02-26 03:01:40 +01:00
|
|
|
* it's not really worthwhile to postpone the check till we know. But
|
|
|
|
* note we do not require caller to provide an expectedDesc.
|
2008-10-31 20:37:56 +01:00
|
|
|
*/
|
|
|
|
if (!rsi || !IsA(rsi, ReturnSetInfo) ||
|
|
|
|
(rsi->allowedModes & SFRM_ValuePerCall) == 0 ||
|
2009-06-11 19:25:39 +02:00
|
|
|
(rsi->allowedModes & SFRM_Materialize) == 0)
|
2008-10-31 20:37:56 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("set-valued function called in context that cannot accept a set")));
|
|
|
|
randomAccess = rsi->allowedModes & SFRM_Materialize_Random;
|
|
|
|
lazyEvalOK = !(rsi->allowedModes & SFRM_Materialize_Preferred);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
randomAccess = false;
|
|
|
|
lazyEvalOK = true;
|
|
|
|
}
|
|
|
|
|
2000-08-24 05:29:15 +02:00
|
|
|
/*
|
2013-03-03 23:39:58 +01:00
|
|
|
* Initialize fcache (build plans) if first time through; or re-initialize
|
|
|
|
* if the cache is stale.
|
2000-08-24 05:29:15 +02:00
|
|
|
*/
|
|
|
|
fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
|
2013-03-03 23:39:58 +01:00
|
|
|
|
|
|
|
if (fcache != NULL)
|
|
|
|
{
|
|
|
|
if (fcache->lxid != MyProc->lxid ||
|
|
|
|
!SubTransactionIsActive(fcache->subxid))
|
|
|
|
{
|
|
|
|
/* It's stale; unlink and delete */
|
|
|
|
fcinfo->flinfo->fn_extra = NULL;
|
|
|
|
MemoryContextDelete(fcache->fcontext);
|
|
|
|
fcache = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2000-08-24 05:29:15 +02:00
|
|
|
if (fcache == NULL)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2020-01-08 17:07:53 +01:00
|
|
|
init_sql_fcache(fcinfo, PG_GET_COLLATION(), lazyEvalOK);
|
2000-08-24 05:29:15 +02:00
|
|
|
fcache = (SQLFunctionCachePtr) fcinfo->flinfo->fn_extra;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2013-03-03 23:39:58 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Switch to context in which the fcache lives. This ensures that our
|
|
|
|
* tuplestore etc will have sufficient lifetime. The sub-executor is
|
2014-05-06 18:12:18 +02:00
|
|
|
* responsible for deleting per-tuple information. (XXX in the case of a
|
2013-03-03 23:39:58 +01:00
|
|
|
* long-lived FmgrInfo, this policy represents more memory leakage, but
|
|
|
|
* it's not entirely clear where to keep stuff instead.)
|
|
|
|
*/
|
|
|
|
oldcontext = MemoryContextSwitchTo(fcache->fcontext);
|
2011-03-01 05:27:18 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Find first unfinished query in function, and note whether it's the
|
|
|
|
* first query.
|
|
|
|
*/
|
2013-03-03 23:39:58 +01:00
|
|
|
eslist = fcache->func_state;
|
2011-03-01 05:27:18 +01:00
|
|
|
es = NULL;
|
|
|
|
is_first = true;
|
|
|
|
foreach(eslc, eslist)
|
|
|
|
{
|
|
|
|
es = (execution_state *) lfirst(eslc);
|
|
|
|
|
|
|
|
while (es && es->status == F_EXEC_DONE)
|
|
|
|
{
|
|
|
|
is_first = false;
|
|
|
|
es = es->next;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (es)
|
|
|
|
break;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2002-12-05 16:50:39 +01:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Convert params to appropriate format if starting a fresh execution. (If
|
|
|
|
* continuing execution, we can re-use prior params.)
|
2002-12-05 16:50:39 +01:00
|
|
|
*/
|
2011-03-01 05:27:18 +01:00
|
|
|
if (is_first && es && es->status == F_EXEC_START)
|
2002-12-05 16:50:39 +01:00
|
|
|
postquel_sub_params(fcache, fcinfo);
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Build tuplestore to hold results, if we don't have one already. Note
|
|
|
|
* it's in the query-lifespan context.
|
2008-10-31 20:37:56 +01:00
|
|
|
*/
|
|
|
|
if (!fcache->tstore)
|
|
|
|
fcache->tstore = tuplestore_begin_heap(randomAccess, false, work_mem);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2008-10-31 20:37:56 +01:00
|
|
|
* Execute each command in the function one after another until we either
|
|
|
|
* run out of commands or get a result row from a lazily-evaluated SELECT.
|
2011-03-01 05:27:18 +01:00
|
|
|
*
|
|
|
|
* Notes about snapshot management:
|
|
|
|
*
|
|
|
|
* In a read-only function, we just use the surrounding query's snapshot.
|
|
|
|
*
|
|
|
|
* In a non-read-only function, we rely on the fact that we'll never
|
|
|
|
* suspend execution between queries of the function: the only reason to
|
2011-04-10 17:42:00 +02:00
|
|
|
* suspend execution before completion is if we are returning a row from a
|
|
|
|
* lazily-evaluated SELECT. So, when first entering this loop, we'll
|
2011-03-01 05:27:18 +01:00
|
|
|
* either start a new query (and push a fresh snapshot) or re-establish
|
2014-05-06 18:12:18 +02:00
|
|
|
* the active snapshot from the existing query descriptor. If we need to
|
2011-03-01 05:27:18 +01:00
|
|
|
* start a new query in a subsequent execution of the loop, either we need
|
|
|
|
* a fresh snapshot (and pushed_snapshot is false) or the existing
|
|
|
|
* snapshot is on the active stack and we can just bump its command ID.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2011-03-01 05:27:18 +01:00
|
|
|
pushed_snapshot = false;
|
2002-08-23 18:41:38 +02:00
|
|
|
while (es)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2009-06-11 16:49:15 +02:00
|
|
|
bool completed;
|
2008-10-31 20:37:56 +01:00
|
|
|
|
|
|
|
if (es->status == F_EXEC_START)
|
2011-03-01 05:27:18 +01:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If not read-only, be sure to advance the command counter for
|
|
|
|
* each command, so that all work to date in this transaction is
|
|
|
|
* visible. Take a new snapshot if we don't have one yet,
|
|
|
|
* otherwise just bump the command ID in the existing snapshot.
|
|
|
|
*/
|
|
|
|
if (!fcache->readonly_func)
|
|
|
|
{
|
|
|
|
CommandCounterIncrement();
|
|
|
|
if (!pushed_snapshot)
|
|
|
|
{
|
|
|
|
PushActiveSnapshot(GetTransactionSnapshot());
|
|
|
|
pushed_snapshot = true;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
UpdateActiveSnapshotCommandId();
|
|
|
|
}
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
postquel_start(es, fcache);
|
2011-03-01 05:27:18 +01:00
|
|
|
}
|
|
|
|
else if (!fcache->readonly_func && !pushed_snapshot)
|
|
|
|
{
|
|
|
|
/* Re-establish active snapshot when re-entering function */
|
|
|
|
PushActiveSnapshot(es->qd->snapshot);
|
|
|
|
pushed_snapshot = true;
|
|
|
|
}
|
2008-10-31 20:37:56 +01:00
|
|
|
|
2008-10-31 22:07:55 +01:00
|
|
|
completed = postquel_getnext(es, fcache);
|
2008-10-31 20:37:56 +01:00
|
|
|
|
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If we ran the command to completion, we can shut it down now. Any
|
|
|
|
* row(s) we need to return are safely stashed in the tuplestore, and
|
|
|
|
* we want to be sure that, for example, AFTER triggers get fired
|
2008-10-31 20:37:56 +01:00
|
|
|
* before we return anything. Also, if the function doesn't return
|
2009-06-11 16:49:15 +02:00
|
|
|
* set, we can shut it down anyway because it must be a SELECT and we
|
|
|
|
* don't care about fetching any more result rows.
|
2008-10-31 20:37:56 +01:00
|
|
|
*/
|
2008-10-31 22:07:55 +01:00
|
|
|
if (completed || !fcache->returnsSet)
|
2008-10-31 20:37:56 +01:00
|
|
|
postquel_end(es);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Break from loop if we didn't shut down (implying we got a
|
2009-06-11 16:49:15 +02:00
|
|
|
* lazily-evaluated row). Otherwise we'll press on till the whole
|
|
|
|
* function is done, relying on the tuplestore to keep hold of the
|
2014-05-06 18:12:18 +02:00
|
|
|
* data to eventually be returned. This is necessary since an
|
2009-06-11 16:49:15 +02:00
|
|
|
* INSERT/UPDATE/DELETE RETURNING that sets the result might be
|
2008-10-31 20:37:56 +01:00
|
|
|
* followed by additional rule-inserted commands, and we want to
|
|
|
|
* finish doing all those commands before we return anything.
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
if (es->status != F_EXEC_DONE)
|
|
|
|
break;
|
2011-03-01 05:27:18 +01:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Advance to next execution_state, which might be in the next list.
|
|
|
|
*/
|
1997-09-07 07:04:48 +02:00
|
|
|
es = es->next;
|
2011-03-01 05:27:18 +01:00
|
|
|
while (!es)
|
|
|
|
{
|
Represent Lists as expansible arrays, not chains of cons-cells.
Originally, Postgres Lists were a more or less exact reimplementation of
Lisp lists, which consist of chains of separately-allocated cons cells,
each having a value and a next-cell link. We'd hacked that once before
(commit d0b4399d8) to add a separate List header, but the data was still
in cons cells. That makes some operations -- notably list_nth() -- O(N),
and it's bulky because of the next-cell pointers and per-cell palloc
overhead, and it's very cache-unfriendly if the cons cells end up
scattered around rather than being adjacent.
In this rewrite, we still have List headers, but the data is in a
resizable array of values, with no next-cell links. Now we need at
most two palloc's per List, and often only one, since we can allocate
some values in the same palloc call as the List header. (Of course,
extending an existing List may require repalloc's to enlarge the array.
But this involves just O(log N) allocations not O(N).)
Of course this is not without downsides. The key difficulty is that
addition or deletion of a list entry may now cause other entries to
move, which it did not before.
For example, that breaks foreach() and sister macros, which historically
used a pointer to the current cons-cell as loop state. We can repair
those macros transparently by making their actual loop state be an
integer list index; the exposed "ListCell *" pointer is no longer state
carried across loop iterations, but is just a derived value. (In
practice, modern compilers can optimize things back to having just one
loop state value, at least for simple cases with inline loop bodies.)
In principle, this is a semantics change for cases where the loop body
inserts or deletes list entries ahead of the current loop index; but
I found no such cases in the Postgres code.
The change is not at all transparent for code that doesn't use foreach()
but chases lists "by hand" using lnext(). The largest share of such
code in the backend is in loops that were maintaining "prev" and "next"
variables in addition to the current-cell pointer, in order to delete
list cells efficiently using list_delete_cell(). However, we no longer
need a previous-cell pointer to delete a list cell efficiently. Keeping
a next-cell pointer doesn't work, as explained above, but we can improve
matters by changing such code to use a regular foreach() loop and then
using the new macro foreach_delete_current() to delete the current cell.
(This macro knows how to update the associated foreach loop's state so
that no cells will be missed in the traversal.)
There remains a nontrivial risk of code assuming that a ListCell *
pointer will remain good over an operation that could now move the list
contents. To help catch such errors, list.c can be compiled with a new
define symbol DEBUG_LIST_MEMORY_USAGE that forcibly moves list contents
whenever that could possibly happen. This makes list operations
significantly more expensive so it's not normally turned on (though it
is on by default if USE_VALGRIND is on).
There are two notable API differences from the previous code:
* lnext() now requires the List's header pointer in addition to the
current cell's address.
* list_delete_cell() no longer requires a previous-cell argument.
These changes are somewhat unfortunate, but on the other hand code using
either function needs inspection to see if it is assuming anything
it shouldn't, so it's not all bad.
Programmers should be aware of these significant performance changes:
* list_nth() and related functions are now O(1); so there's no
major access-speed difference between a list and an array.
* Inserting or deleting a list element now takes time proportional to
the distance to the end of the list, due to moving the array elements.
(However, it typically *doesn't* require palloc or pfree, so except in
long lists it's probably still faster than before.) Notably, lcons()
used to be about the same cost as lappend(), but that's no longer true
if the list is long. Code that uses lcons() and list_delete_first()
to maintain a stack might usefully be rewritten to push and pop at the
end of the list rather than the beginning.
* There are now list_insert_nth...() and list_delete_nth...() functions
that add or remove a list cell identified by index. These have the
data-movement penalty explained above, but there's no search penalty.
* list_concat() and variants now copy the second list's data into
storage belonging to the first list, so there is no longer any
sharing of cells between the input lists. The second argument is
now declared "const List *" to reflect that it isn't changed.
This patch just does the minimum needed to get the new implementation
in place and fix bugs exposed by the regression tests. As suggested
by the foregoing, there's a fair amount of followup work remaining to
do.
Also, the ENABLE_LIST_COMPAT macros are finally removed in this
commit. Code using those should have been gone a dozen years ago.
Patch by me; thanks to David Rowley, Jesper Pedersen, and others
for review.
Discussion: https://postgr.es/m/11587.1550975080@sss.pgh.pa.us
2019-07-15 19:41:58 +02:00
|
|
|
eslc = lnext(eslist, eslc);
|
2011-03-01 05:27:18 +01:00
|
|
|
if (!eslc)
|
|
|
|
break; /* end of function */
|
|
|
|
|
|
|
|
es = (execution_state *) lfirst(eslc);
|
|
|
|
|
|
|
|
/*
|
2011-04-10 17:42:00 +02:00
|
|
|
* Flush the current snapshot so that we will take a new one for
|
2014-05-06 18:12:18 +02:00
|
|
|
* the new query list. This ensures that new snaps are taken at
|
2011-04-10 17:42:00 +02:00
|
|
|
* original-query boundaries, matching the behavior of interactive
|
|
|
|
* execution.
|
2011-03-01 05:27:18 +01:00
|
|
|
*/
|
|
|
|
if (pushed_snapshot)
|
|
|
|
{
|
|
|
|
PopActiveSnapshot();
|
|
|
|
pushed_snapshot = false;
|
|
|
|
}
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1997-08-29 11:05:57 +02:00
|
|
|
/*
|
2008-10-31 20:37:56 +01:00
|
|
|
* The tuplestore now contains whatever row(s) we are supposed to return.
|
1997-08-29 11:05:57 +02:00
|
|
|
*/
|
2008-10-31 20:37:56 +01:00
|
|
|
if (fcache->returnsSet)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
ReturnSetInfo *rsi = (ReturnSetInfo *) fcinfo->resultinfo;
|
|
|
|
|
|
|
|
if (es)
|
1997-09-07 07:04:48 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If we stopped short of being done, we must have a lazy-eval
|
|
|
|
* row.
|
2008-10-31 20:37:56 +01:00
|
|
|
*/
|
|
|
|
Assert(es->lazyEval);
|
|
|
|
/* Re-use the junkfilter's output slot to fetch back the tuple */
|
|
|
|
Assert(fcache->junkFilter);
|
|
|
|
slot = fcache->junkFilter->jf_resultSlot;
|
2009-03-27 19:30:21 +01:00
|
|
|
if (!tuplestore_gettupleslot(fcache->tstore, true, false, slot))
|
2008-10-31 20:37:56 +01:00
|
|
|
elog(ERROR, "failed to fetch lazy-eval tuple");
|
|
|
|
/* Extract the result as a datum, and copy out from the slot */
|
|
|
|
result = postquel_get_single_result(slot, fcinfo,
|
|
|
|
fcache, oldcontext);
|
|
|
|
/* Clear the tuplestore, but keep it for next time */
|
|
|
|
/* NB: this might delete the slot's content, but we don't care */
|
|
|
|
tuplestore_clear(fcache->tstore);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
|
|
|
* Let caller know we're not finished.
|
|
|
|
*/
|
|
|
|
rsi->isDone = ExprMultipleResult;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Ensure we will get shut down cleanly if the exprcontext is not
|
|
|
|
* run to completion.
|
|
|
|
*/
|
|
|
|
if (!fcache->shutdown_reg)
|
|
|
|
{
|
|
|
|
RegisterExprContextCallback(rsi->econtext,
|
|
|
|
ShutdownSQLFunction,
|
|
|
|
PointerGetDatum(fcache));
|
|
|
|
fcache->shutdown_reg = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (fcache->lazyEval)
|
2000-08-24 05:29:15 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* We are done with a lazy evaluation. Clean up.
|
2008-10-31 20:37:56 +01:00
|
|
|
*/
|
|
|
|
tuplestore_clear(fcache->tstore);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Let caller know we're finished.
|
|
|
|
*/
|
|
|
|
rsi->isDone = ExprEndResult;
|
2000-08-24 05:29:15 +02:00
|
|
|
|
|
|
|
fcinfo->isnull = true;
|
|
|
|
result = (Datum) 0;
|
2002-05-12 22:10:05 +02:00
|
|
|
|
|
|
|
/* Deregister shutdown callback, if we made one */
|
|
|
|
if (fcache->shutdown_reg)
|
|
|
|
{
|
|
|
|
UnregisterExprContextCallback(rsi->econtext,
|
|
|
|
ShutdownSQLFunction,
|
|
|
|
PointerGetDatum(fcache));
|
|
|
|
fcache->shutdown_reg = false;
|
|
|
|
}
|
2000-08-24 05:29:15 +02:00
|
|
|
}
|
2008-10-31 20:37:56 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
2014-05-06 18:12:18 +02:00
|
|
|
* We are done with a non-lazy evaluation. Return whatever is in
|
|
|
|
* the tuplestore. (It is now caller's responsibility to free the
|
2009-06-11 16:49:15 +02:00
|
|
|
* tuplestore when done.)
|
2008-10-31 20:37:56 +01:00
|
|
|
*/
|
|
|
|
rsi->returnMode = SFRM_Materialize;
|
|
|
|
rsi->setResult = fcache->tstore;
|
|
|
|
fcache->tstore = NULL;
|
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
|
|
|
/* must copy desc because execSRF.c will free it */
|
2008-10-31 20:37:56 +01:00
|
|
|
if (fcache->junkFilter)
|
|
|
|
rsi->setDesc = CreateTupleDescCopy(fcache->junkFilter->jf_cleanTupType);
|
2000-08-24 05:29:15 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
fcinfo->isnull = true;
|
|
|
|
result = (Datum) 0;
|
2000-08-24 05:29:15 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Deregister shutdown callback, if we made one */
|
|
|
|
if (fcache->shutdown_reg)
|
|
|
|
{
|
|
|
|
UnregisterExprContextCallback(rsi->econtext,
|
|
|
|
ShutdownSQLFunction,
|
|
|
|
PointerGetDatum(fcache));
|
|
|
|
fcache->shutdown_reg = false;
|
|
|
|
}
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2008-10-31 20:37:56 +01:00
|
|
|
else
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Non-set function. If we got a row, return it; else return NULL.
|
|
|
|
*/
|
|
|
|
if (fcache->junkFilter)
|
|
|
|
{
|
|
|
|
/* Re-use the junkfilter's output slot to fetch back the tuple */
|
|
|
|
slot = fcache->junkFilter->jf_resultSlot;
|
2009-03-27 19:30:21 +01:00
|
|
|
if (tuplestore_gettupleslot(fcache->tstore, true, false, slot))
|
2008-10-31 20:37:56 +01:00
|
|
|
result = postquel_get_single_result(slot, fcinfo,
|
|
|
|
fcache, oldcontext);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fcinfo->isnull = true;
|
|
|
|
result = (Datum) 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2018-03-02 14:57:38 +01:00
|
|
|
/* Should only get here for VOID functions and procedures */
|
|
|
|
Assert(fcache->rettype == VOIDOID);
|
2008-10-31 20:37:56 +01:00
|
|
|
fcinfo->isnull = true;
|
|
|
|
result = (Datum) 0;
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Clear the tuplestore, but keep it for next time */
|
|
|
|
tuplestore_clear(fcache->tstore);
|
|
|
|
}
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
/* Pop snapshot if we have pushed one */
|
|
|
|
if (pushed_snapshot)
|
|
|
|
PopActiveSnapshot();
|
|
|
|
|
2000-08-24 05:29:15 +02:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* If we've gone through every command in the function, we are done. Reset
|
|
|
|
* the execution states to start over again on next call.
|
2000-08-24 05:29:15 +02:00
|
|
|
*/
|
2008-10-31 20:37:56 +01:00
|
|
|
if (es == NULL)
|
2000-08-24 05:29:15 +02:00
|
|
|
{
|
2011-03-01 05:27:18 +01:00
|
|
|
foreach(eslc, fcache->func_state)
|
2002-05-12 22:10:05 +02:00
|
|
|
{
|
2011-03-01 05:27:18 +01:00
|
|
|
es = (execution_state *) lfirst(eslc);
|
|
|
|
while (es)
|
|
|
|
{
|
|
|
|
es->status = F_EXEC_START;
|
|
|
|
es = es->next;
|
|
|
|
}
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
2000-08-24 05:29:15 +02:00
|
|
|
}
|
2000-07-12 04:37:39 +02:00
|
|
|
|
2003-07-28 20:33:18 +02:00
|
|
|
error_context_stack = sqlerrcontext.previous;
|
|
|
|
|
2000-07-12 04:37:39 +02:00
|
|
|
MemoryContextSwitchTo(oldcontext);
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
return result;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
2002-05-12 22:10:05 +02:00
|
|
|
|
2003-07-28 20:33:18 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* error context callback to let us supply a call-stack traceback
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sql_exec_error_callback(void *arg)
|
|
|
|
{
|
|
|
|
FmgrInfo *flinfo = (FmgrInfo *) arg;
|
|
|
|
SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) flinfo->fn_extra;
|
2004-03-21 23:29:11 +01:00
|
|
|
int syntaxerrposition;
|
2003-07-28 20:33:18 +02:00
|
|
|
|
2010-03-19 23:54:41 +01:00
|
|
|
/*
|
|
|
|
* We can do nothing useful if init_sql_fcache() didn't get as far as
|
|
|
|
* saving the function name
|
|
|
|
*/
|
|
|
|
if (fcache == NULL || fcache->fname == NULL)
|
|
|
|
return;
|
2004-03-21 23:29:11 +01:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* If there is a syntax error position, convert to internal syntax error
|
2004-03-21 23:29:11 +01:00
|
|
|
*/
|
|
|
|
syntaxerrposition = geterrposition();
|
2010-03-19 23:54:41 +01:00
|
|
|
if (syntaxerrposition > 0 && fcache->src != NULL)
|
2004-03-21 23:29:11 +01:00
|
|
|
{
|
|
|
|
errposition(0);
|
|
|
|
internalerrposition(syntaxerrposition);
|
2010-03-19 23:54:41 +01:00
|
|
|
internalerrquery(fcache->src);
|
2004-03-21 23:29:11 +01:00
|
|
|
}
|
2003-07-28 20:33:18 +02:00
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* Try to determine where in the function we failed. If there is a query
|
2014-05-06 18:12:18 +02:00
|
|
|
* with non-null QueryDesc, finger it. (We check this rather than looking
|
2005-10-15 04:49:52 +02:00
|
|
|
* for F_EXEC_RUN state, so that errors during ExecutorStart or
|
|
|
|
* ExecutorEnd are blamed on the appropriate query; see postquel_start and
|
|
|
|
* postquel_end.)
|
2003-07-28 20:33:18 +02:00
|
|
|
*/
|
2010-03-19 23:54:41 +01:00
|
|
|
if (fcache->func_state)
|
2003-07-28 20:33:18 +02:00
|
|
|
{
|
|
|
|
execution_state *es;
|
2003-08-04 02:43:34 +02:00
|
|
|
int query_num;
|
2011-03-01 05:27:18 +01:00
|
|
|
ListCell *lc;
|
2003-07-28 20:33:18 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
es = NULL;
|
2003-07-28 20:33:18 +02:00
|
|
|
query_num = 1;
|
2011-03-01 05:27:18 +01:00
|
|
|
foreach(lc, fcache->func_state)
|
2003-07-28 20:33:18 +02:00
|
|
|
{
|
2011-03-01 05:27:18 +01:00
|
|
|
es = (execution_state *) lfirst(lc);
|
|
|
|
while (es)
|
2003-07-28 20:33:18 +02:00
|
|
|
{
|
2011-03-01 05:27:18 +01:00
|
|
|
if (es->qd)
|
|
|
|
{
|
|
|
|
errcontext("SQL function \"%s\" statement %d",
|
|
|
|
fcache->fname, query_num);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
es = es->next;
|
2003-07-28 20:33:18 +02:00
|
|
|
}
|
2011-03-01 05:27:18 +01:00
|
|
|
if (es)
|
|
|
|
break;
|
2003-07-28 20:33:18 +02:00
|
|
|
query_num++;
|
|
|
|
}
|
|
|
|
if (es == NULL)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* couldn't identify a running query; might be function entry,
|
|
|
|
* function exit, or between queries.
|
|
|
|
*/
|
2010-03-19 23:54:41 +01:00
|
|
|
errcontext("SQL function \"%s\"", fcache->fname);
|
2003-07-28 20:33:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-03-19 23:54:41 +01:00
|
|
|
/*
|
2010-07-06 21:19:02 +02:00
|
|
|
* Assume we failed during init_sql_fcache(). (It's possible that the
|
|
|
|
* function actually has an empty body, but in that case we may as
|
|
|
|
* well report all errors as being "during startup".)
|
2010-03-19 23:54:41 +01:00
|
|
|
*/
|
|
|
|
errcontext("SQL function \"%s\" during startup", fcache->fname);
|
2003-07-28 20:33:18 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
/*
|
|
|
|
* callback function in case a function-returning-set needs to be shut down
|
|
|
|
* before it has been run to completion
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
ShutdownSQLFunction(Datum arg)
|
|
|
|
{
|
|
|
|
SQLFunctionCachePtr fcache = (SQLFunctionCachePtr) DatumGetPointer(arg);
|
2011-03-01 05:27:18 +01:00
|
|
|
execution_state *es;
|
2011-04-10 17:42:00 +02:00
|
|
|
ListCell *lc;
|
2002-05-12 22:10:05 +02:00
|
|
|
|
2011-03-01 05:27:18 +01:00
|
|
|
foreach(lc, fcache->func_state)
|
2002-05-12 22:10:05 +02:00
|
|
|
{
|
2011-03-01 05:27:18 +01:00
|
|
|
es = (execution_state *) lfirst(lc);
|
|
|
|
while (es)
|
|
|
|
{
|
|
|
|
/* Shut down anything still running */
|
|
|
|
if (es->status == F_EXEC_RUN)
|
|
|
|
{
|
|
|
|
/* Re-establish active snapshot for any called functions */
|
|
|
|
if (!fcache->readonly_func)
|
|
|
|
PushActiveSnapshot(es->qd->snapshot);
|
|
|
|
|
|
|
|
postquel_end(es);
|
|
|
|
|
|
|
|
if (!fcache->readonly_func)
|
|
|
|
PopActiveSnapshot();
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Reset states to START in case we're called again */
|
|
|
|
es->status = F_EXEC_START;
|
|
|
|
es = es->next;
|
|
|
|
}
|
2002-05-12 22:10:05 +02:00
|
|
|
}
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/* Release tuplestore if we have one */
|
|
|
|
if (fcache->tstore)
|
|
|
|
tuplestore_end(fcache->tstore);
|
|
|
|
fcache->tstore = NULL;
|
|
|
|
|
2002-05-12 22:10:05 +02:00
|
|
|
/* execUtils will deregister the callback... */
|
|
|
|
fcache->shutdown_reg = false;
|
|
|
|
}
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2018-03-14 16:47:21 +01:00
|
|
|
/*
|
|
|
|
* check_sql_fn_statements
|
|
|
|
*
|
|
|
|
* Check statements in an SQL function. Error out if there is anything that
|
|
|
|
* is not acceptable.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
check_sql_fn_statements(List *queryTreeList)
|
|
|
|
{
|
|
|
|
ListCell *lc;
|
|
|
|
|
|
|
|
foreach(lc, queryTreeList)
|
|
|
|
{
|
|
|
|
Query *query = lfirst_node(Query, lc);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Disallow procedures with output arguments. The current
|
|
|
|
* implementation would just throw the output values away, unless the
|
|
|
|
* statement is the last one. Per SQL standard, we should assign the
|
|
|
|
* output values by name. By disallowing this here, we preserve an
|
|
|
|
* opportunity for future improvement.
|
|
|
|
*/
|
|
|
|
if (query->commandType == CMD_UTILITY &&
|
|
|
|
IsA(query->utilityStmt, CallStmt))
|
|
|
|
{
|
|
|
|
CallStmt *stmt = castNode(CallStmt, query->utilityStmt);
|
|
|
|
HeapTuple tuple;
|
|
|
|
int numargs;
|
|
|
|
Oid *argtypes;
|
|
|
|
char **argnames;
|
|
|
|
char *argmodes;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
tuple = SearchSysCache1(PROCOID, ObjectIdGetDatum(stmt->funcexpr->funcid));
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
elog(ERROR, "cache lookup failed for function %u", stmt->funcexpr->funcid);
|
|
|
|
numargs = get_func_arg_info(tuple, &argtypes, &argnames, &argmodes);
|
|
|
|
ReleaseSysCache(tuple);
|
|
|
|
|
|
|
|
for (i = 0; i < numargs; i++)
|
|
|
|
{
|
|
|
|
if (argmodes && (argmodes[i] == PROARGMODE_INOUT || argmodes[i] == PROARGMODE_OUT))
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
|
|
|
errmsg("calling procedures with output arguments is not supported in SQL functions")));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2004-10-07 20:38:51 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* check_sql_fn_retval() -- check return value of a list of sql parse trees.
|
|
|
|
*
|
2008-10-31 20:37:56 +01:00
|
|
|
* The return value of a sql function is the value returned by the last
|
2020-01-08 17:07:53 +01:00
|
|
|
* canSetTag query in the function. We do some ad-hoc type checking and
|
|
|
|
* coercion here to ensure that the function returns what it's supposed to.
|
|
|
|
* Note that we may actually modify the last query to make it match!
|
2004-10-07 20:38:51 +02:00
|
|
|
*
|
2007-04-02 20:49:29 +02:00
|
|
|
* This function returns true if the sql function returns the entire tuple
|
2009-12-14 03:15:54 +01:00
|
|
|
* result of its final statement, or false if it returns just the first column
|
|
|
|
* result of that statement. It throws an error if the final statement doesn't
|
|
|
|
* return the right type at all.
|
2004-10-07 20:38:51 +02:00
|
|
|
*
|
2009-12-14 03:15:54 +01:00
|
|
|
* Note that because we allow "SELECT rowtype_expression", the result can be
|
|
|
|
* false even when the declared function return type is a rowtype.
|
|
|
|
*
|
2020-01-08 17:07:53 +01:00
|
|
|
* For a polymorphic function the passed rettype must be the actual resolved
|
2020-03-17 19:54:46 +01:00
|
|
|
* output type of the function. (This means we can't check the type during
|
|
|
|
* function definition of a polymorphic function.) If we do see a polymorphic
|
|
|
|
* rettype we'll throw an error, saying it is not a supported rettype.
|
|
|
|
*
|
|
|
|
* If the function returns composite, the passed rettupdesc should describe
|
|
|
|
* the expected output. If rettupdesc is NULL, we can't verify that the
|
|
|
|
* output matches; that should only happen in fmgr_sql_validator(), or when
|
|
|
|
* the function returns RECORD and the caller doesn't actually care which
|
|
|
|
* composite type it is.
|
|
|
|
*
|
2020-01-08 17:07:53 +01:00
|
|
|
* (Typically, rettype and rettupdesc are computed by get_call_result_type
|
|
|
|
* or a sibling function.)
|
|
|
|
*
|
|
|
|
* In addition to coercing individual output columns, we can modify the
|
|
|
|
* output to include dummy NULL columns for any dropped columns appearing
|
|
|
|
* in rettupdesc. This is done only if the caller asks for it.
|
2008-03-18 23:04:14 +01:00
|
|
|
*
|
2020-01-08 17:07:53 +01:00
|
|
|
* If resultTargetList isn't NULL, then *resultTargetList is set to the
|
|
|
|
* targetlist that defines the final statement's result. Exception: if the
|
|
|
|
* function is defined to return VOID then *resultTargetList is set to NIL.
|
2004-10-07 20:38:51 +02:00
|
|
|
*/
|
|
|
|
bool
|
2020-01-08 17:07:53 +01:00
|
|
|
check_sql_fn_retval(List *queryTreeList,
|
|
|
|
Oid rettype, TupleDesc rettupdesc,
|
|
|
|
bool insertDroppedCols,
|
|
|
|
List **resultTargetList)
|
2004-10-07 20:38:51 +02:00
|
|
|
{
|
2020-01-08 17:07:53 +01:00
|
|
|
bool is_tuple_result = false;
|
2004-10-07 20:38:51 +02:00
|
|
|
Query *parse;
|
2020-01-08 17:07:53 +01:00
|
|
|
ListCell *parse_cell;
|
2004-10-07 20:38:51 +02:00
|
|
|
List *tlist;
|
|
|
|
int tlistlen;
|
2020-01-08 17:07:53 +01:00
|
|
|
bool tlist_is_modifiable;
|
2005-04-01 00:46:33 +02:00
|
|
|
char fn_typtype;
|
2020-01-08 17:07:53 +01:00
|
|
|
List *upper_tlist = NIL;
|
|
|
|
bool upper_tlist_nontrivial = false;
|
2008-10-31 20:37:56 +01:00
|
|
|
ListCell *lc;
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2020-01-08 17:07:53 +01:00
|
|
|
if (resultTargetList)
|
|
|
|
*resultTargetList = NIL; /* initialize in case of VOID result */
|
2017-11-30 14:46:13 +01:00
|
|
|
|
2018-03-02 14:57:38 +01:00
|
|
|
/*
|
|
|
|
* If it's declared to return VOID, we don't care what's in the function.
|
|
|
|
* (This takes care of the procedure case, as well.)
|
|
|
|
*/
|
|
|
|
if (rettype == VOIDOID)
|
2017-11-30 14:46:13 +01:00
|
|
|
return false;
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
/*
|
2009-06-11 16:49:15 +02:00
|
|
|
* Find the last canSetTag query in the list. This isn't necessarily the
|
|
|
|
* last parsetree, because rule rewriting can insert queries after what
|
|
|
|
* the user wrote.
|
2008-10-31 20:37:56 +01:00
|
|
|
*/
|
|
|
|
parse = NULL;
|
2020-01-08 17:07:53 +01:00
|
|
|
parse_cell = NULL;
|
2008-10-31 20:37:56 +01:00
|
|
|
foreach(lc, queryTreeList)
|
2004-10-07 20:38:51 +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, lc);
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
if (q->canSetTag)
|
2020-01-08 17:07:53 +01:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
parse = q;
|
2020-01-08 17:07:53 +01:00
|
|
|
parse_cell = lc;
|
|
|
|
}
|
2008-10-31 20:37:56 +01:00
|
|
|
}
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2006-08-12 22:05:56 +02:00
|
|
|
/*
|
2008-10-31 20:37:56 +01:00
|
|
|
* If it's a plain SELECT, it returns whatever the targetlist says.
|
2009-06-11 16:49:15 +02:00
|
|
|
* Otherwise, if it's INSERT/UPDATE/DELETE with RETURNING, it returns
|
|
|
|
* that. Otherwise, the function return type must be VOID.
|
2007-04-02 20:49:29 +02:00
|
|
|
*
|
2007-11-15 22:14:46 +01:00
|
|
|
* Note: eventually replace this test with QueryReturnsTuples? We'd need
|
2009-06-11 16:49:15 +02:00
|
|
|
* a more general method of determining the output type, though. Also, it
|
|
|
|
* seems too dangerous to consider FETCH or EXECUTE as returning a
|
2008-10-31 20:37:56 +01:00
|
|
|
* determinable rowtype, since they depend on relatively short-lived
|
|
|
|
* entities.
|
2004-10-07 20:38:51 +02:00
|
|
|
*/
|
2008-10-31 20:37:56 +01:00
|
|
|
if (parse &&
|
Change representation of statement lists, and add statement location info.
This patch makes several changes that improve the consistency of
representation of lists of statements. It's always been the case
that the output of parse analysis is a list of Query nodes, whatever
the types of the individual statements in the list. This patch brings
similar consistency to the outputs of raw parsing and planning steps:
* The output of raw parsing is now always a list of RawStmt nodes;
the statement-type-dependent nodes are one level down from that.
* The output of pg_plan_queries() is now always a list of PlannedStmt
nodes, even for utility statements. In the case of a utility statement,
"planning" just consists of wrapping a CMD_UTILITY PlannedStmt around
the utility node. This list representation is now used in Portal and
CachedPlan plan lists, replacing the former convention of intermixing
PlannedStmts with bare utility-statement nodes.
Now, every list of statements has a consistent head-node type depending
on how far along it is in processing. This allows changing many places
that formerly used generic "Node *" pointers to use a more specific
pointer type, thus reducing the number of IsA() tests and casts needed,
as well as improving code clarity.
Also, the post-parse-analysis representation of DECLARE CURSOR is changed
so that it looks more like EXPLAIN, PREPARE, etc. That is, the contained
SELECT remains a child of the DeclareCursorStmt rather than getting flipped
around to be the other way. It's now true for both Query and PlannedStmt
that utilityStmt is non-null if and only if commandType is CMD_UTILITY.
That allows simplifying a lot of places that were testing both fields.
(I think some of those were just defensive programming, but in many places,
it was actually necessary to avoid confusing DECLARE CURSOR with SELECT.)
Because PlannedStmt carries a canSetTag field, we're also able to get rid
of some ad-hoc rules about how to reconstruct canSetTag for a bare utility
statement; specifically, the assumption that a utility is canSetTag if and
only if it's the only one in its list. While I see no near-term need for
relaxing that restriction, it's nice to get rid of the ad-hocery.
The API of ProcessUtility() is changed so that what it's passed is the
wrapper PlannedStmt not just the bare utility statement. This will affect
all users of ProcessUtility_hook, but the changes are pretty trivial; see
the affected contrib modules for examples of the minimum change needed.
(Most compilers should give pointer-type-mismatch warnings for uncorrected
code.)
There's also a change in the API of ExplainOneQuery_hook, to pass through
cursorOptions instead of expecting hook functions to know what to pick.
This is needed because of the DECLARE CURSOR changes, but really should
have been done in 9.6; it's unlikely that any extant hook functions
know about using CURSOR_OPT_PARALLEL_OK.
Finally, teach gram.y to save statement boundary locations in RawStmt
nodes, and pass those through to Query and PlannedStmt nodes. This allows
more intelligent handling of cases where a source query string contains
multiple statements. This patch doesn't actually do anything with the
information, but a follow-on patch will. (Passing this information through
cleanly is the true motivation for these changes; while I think this is all
good cleanup, it's unlikely we'd have bothered without this end goal.)
catversion bump because addition of location fields to struct Query
affects stored rules.
This patch is by me, but it owes a good deal to Fabien Coelho who did
a lot of preliminary work on the problem, and also reviewed the patch.
Discussion: https://postgr.es/m/alpine.DEB.2.20.1612200926310.29821@lancre
2017-01-14 22:02:35 +01:00
|
|
|
parse->commandType == CMD_SELECT)
|
2008-10-31 20:37:56 +01:00
|
|
|
{
|
|
|
|
tlist = parse->targetList;
|
2020-01-08 17:07:53 +01:00
|
|
|
/* tlist is modifiable unless it's a dummy in a setop query */
|
|
|
|
tlist_is_modifiable = (parse->setOperations == NULL);
|
2008-10-31 20:37:56 +01:00
|
|
|
}
|
|
|
|
else if (parse &&
|
|
|
|
(parse->commandType == CMD_INSERT ||
|
|
|
|
parse->commandType == CMD_UPDATE ||
|
|
|
|
parse->commandType == CMD_DELETE) &&
|
|
|
|
parse->returningList)
|
2004-10-07 20:38:51 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
tlist = parse->returningList;
|
2020-01-08 17:07:53 +01:00
|
|
|
/* returningList can always be modified */
|
|
|
|
tlist_is_modifiable = true;
|
2008-10-31 20:37:56 +01:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Empty function body, or last statement is a utility command */
|
2018-03-02 14:57:38 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("return type mismatch in function declared to return %s",
|
|
|
|
format_type_be(rettype)),
|
|
|
|
errdetail("Function's final statement must be SELECT or INSERT/UPDATE/DELETE RETURNING.")));
|
|
|
|
return false; /* keep compiler quiet */
|
2004-10-07 20:38:51 +02:00
|
|
|
}
|
|
|
|
|
2007-04-02 20:49:29 +02:00
|
|
|
/*
|
2008-10-31 20:37:56 +01:00
|
|
|
* OK, check that the targetlist returns something matching the declared
|
2020-01-08 17:07:53 +01:00
|
|
|
* type, and modify it if necessary. If possible, we insert any coercion
|
|
|
|
* steps right into the final statement's targetlist. However, that might
|
|
|
|
* risk changes in the statement's semantics --- we can't safely change
|
|
|
|
* the output type of a grouping column, for instance. In such cases we
|
|
|
|
* handle coercions by inserting an extra level of Query that effectively
|
|
|
|
* just does a projection.
|
2007-04-02 20:49:29 +02:00
|
|
|
*/
|
2004-10-07 20:38:51 +02:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Count the non-junk entries in the result targetlist.
|
|
|
|
*/
|
|
|
|
tlistlen = ExecCleanTargetListLength(tlist);
|
|
|
|
|
2005-04-01 00:46:33 +02:00
|
|
|
fn_typtype = get_typtype(rettype);
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2007-04-02 05:49:42 +02:00
|
|
|
if (fn_typtype == TYPTYPE_BASE ||
|
|
|
|
fn_typtype == TYPTYPE_DOMAIN ||
|
2007-04-02 20:49:29 +02:00
|
|
|
fn_typtype == TYPTYPE_ENUM ||
|
2018-03-02 14:57:38 +01:00
|
|
|
fn_typtype == TYPTYPE_RANGE)
|
2004-10-07 20:38:51 +02:00
|
|
|
{
|
|
|
|
/*
|
2008-03-18 23:04:14 +01:00
|
|
|
* For scalar-type returns, the target list must have exactly one
|
2020-01-08 17:07:53 +01:00
|
|
|
* non-junk entry, and its type must be coercible to rettype.
|
2004-10-07 20:38:51 +02:00
|
|
|
*/
|
2008-03-18 23:04:14 +01:00
|
|
|
TargetEntry *tle;
|
|
|
|
|
2004-10-07 20:38:51 +02:00
|
|
|
if (tlistlen != 1)
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
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("return type mismatch in function declared to return %s",
|
|
|
|
format_type_be(rettype)),
|
|
|
|
errdetail("Final statement must return exactly one column.")));
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2008-03-18 23:04:14 +01:00
|
|
|
/* We assume here that non-junk TLEs must come first in tlists */
|
|
|
|
tle = (TargetEntry *) linitial(tlist);
|
|
|
|
Assert(!tle->resjunk);
|
|
|
|
|
2020-01-08 17:07:53 +01:00
|
|
|
if (!coerce_fn_result_column(tle, rettype, -1,
|
|
|
|
tlist_is_modifiable,
|
|
|
|
&upper_tlist,
|
|
|
|
&upper_tlist_nontrivial))
|
2004-10-07 20:38:51 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
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("return type mismatch in function declared to return %s",
|
|
|
|
format_type_be(rettype)),
|
2004-10-07 20:38:51 +02:00
|
|
|
errdetail("Actual return type is %s.",
|
2020-01-08 17:07:53 +01:00
|
|
|
format_type_be(exprType((Node *) tle->expr)))));
|
2004-10-07 20:38:51 +02:00
|
|
|
}
|
2007-04-02 05:49:42 +02:00
|
|
|
else if (fn_typtype == TYPTYPE_COMPOSITE || rettype == RECORDOID)
|
2004-10-07 20:38:51 +02:00
|
|
|
{
|
2017-10-26 19:47:45 +02:00
|
|
|
/*
|
|
|
|
* Returns a rowtype.
|
|
|
|
*
|
|
|
|
* Note that we will not consider a domain over composite to be a
|
|
|
|
* "rowtype" return type; it goes through the scalar case above. This
|
2020-01-08 17:07:53 +01:00
|
|
|
* is because we only provide column-by-column implicit casting, and
|
|
|
|
* will not cast the complete record result. So the only way to
|
|
|
|
* produce a domain-over-composite result is to compute it as an
|
|
|
|
* explicit single-column result. The single-composite-column code
|
|
|
|
* path just below could handle such cases, but it won't be reached.
|
2017-10-26 19:47:45 +02:00
|
|
|
*/
|
2005-10-15 04:49:52 +02:00
|
|
|
int tupnatts; /* physical number of columns in tuple */
|
|
|
|
int tuplogcols; /* # of nondeleted columns in tuple */
|
|
|
|
int colindex; /* physical column index */
|
2004-10-07 20:38:51 +02:00
|
|
|
|
|
|
|
/*
|
2020-01-08 17:07:53 +01:00
|
|
|
* If the target list has one non-junk entry, and that expression has
|
|
|
|
* or can be coerced to the declared return type, take it as the
|
|
|
|
* result. This allows, for example, 'SELECT func2()', where func2
|
|
|
|
* has the same composite return type as the function that's calling
|
|
|
|
* it. This provision creates some ambiguity --- maybe the expression
|
|
|
|
* was meant to be the lone field of the composite result --- but it
|
|
|
|
* works well enough as long as we don't get too enthusiastic about
|
|
|
|
* inventing coercions from scalar to composite types.
|
2010-12-01 06:53:18 +01:00
|
|
|
*
|
2020-01-08 17:07:53 +01:00
|
|
|
* XXX Note that if rettype is RECORD and the expression is of a named
|
|
|
|
* composite type, or vice versa, this coercion will succeed, whether
|
|
|
|
* or not the record type really matches. For the moment we rely on
|
2010-12-01 06:53:18 +01:00
|
|
|
* runtime type checking to catch any discrepancy, but it'd be nice to
|
|
|
|
* do better at parse time.
|
2004-10-07 20:38:51 +02:00
|
|
|
*/
|
|
|
|
if (tlistlen == 1)
|
|
|
|
{
|
2008-03-18 23:04:14 +01:00
|
|
|
TargetEntry *tle = (TargetEntry *) linitial(tlist);
|
|
|
|
|
|
|
|
Assert(!tle->resjunk);
|
2020-01-08 17:07:53 +01:00
|
|
|
if (coerce_fn_result_column(tle, rettype, -1,
|
|
|
|
tlist_is_modifiable,
|
|
|
|
&upper_tlist,
|
|
|
|
&upper_tlist_nontrivial))
|
2008-03-18 23:04:14 +01:00
|
|
|
{
|
2020-01-08 17:07:53 +01:00
|
|
|
/* Note that we're NOT setting is_tuple_result */
|
|
|
|
goto tlist_coercion_finished;
|
2008-03-18 23:04:14 +01:00
|
|
|
}
|
2004-10-07 20:38:51 +02:00
|
|
|
}
|
|
|
|
|
2017-10-26 19:47:45 +02:00
|
|
|
/*
|
2020-01-08 17:07:53 +01:00
|
|
|
* If the caller didn't provide an expected tupdesc, we can't do any
|
|
|
|
* further checking. Assume we're returning the whole tuple.
|
2017-10-26 19:47:45 +02:00
|
|
|
*/
|
2020-01-08 17:07:53 +01:00
|
|
|
if (rettupdesc == NULL)
|
2005-04-01 00:46:33 +02:00
|
|
|
{
|
2020-01-08 17:07:53 +01:00
|
|
|
/* Return tlist if requested */
|
|
|
|
if (resultTargetList)
|
|
|
|
*resultTargetList = tlist;
|
2005-04-01 00:46:33 +02:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2004-10-07 20:38:51 +02:00
|
|
|
/*
|
2020-01-08 17:07:53 +01:00
|
|
|
* Verify that the targetlist matches the return tuple type. We scan
|
|
|
|
* the non-resjunk columns, and coerce them if necessary to match the
|
|
|
|
* datatypes of the non-deleted attributes. For deleted attributes,
|
|
|
|
* insert NULL result columns if the caller asked for that.
|
2004-10-07 20:38:51 +02:00
|
|
|
*/
|
2020-01-08 17:07:53 +01:00
|
|
|
tupnatts = rettupdesc->natts;
|
2005-04-01 00:46:33 +02:00
|
|
|
tuplogcols = 0; /* we'll count nondeleted cols as we go */
|
2004-10-07 20:38:51 +02:00
|
|
|
colindex = 0;
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
foreach(lc, tlist)
|
2004-10-07 20:38:51 +02:00
|
|
|
{
|
2008-10-31 20:37:56 +01:00
|
|
|
TargetEntry *tle = (TargetEntry *) lfirst(lc);
|
2004-10-07 20:38:51 +02:00
|
|
|
Form_pg_attribute attr;
|
|
|
|
|
2020-01-08 17:07:53 +01:00
|
|
|
/* resjunk columns can simply be ignored */
|
2005-04-06 18:34:07 +02:00
|
|
|
if (tle->resjunk)
|
2004-10-07 20:38:51 +02:00
|
|
|
continue;
|
|
|
|
|
|
|
|
do
|
|
|
|
{
|
|
|
|
colindex++;
|
2005-04-01 00:46:33 +02:00
|
|
|
if (colindex > tupnatts)
|
2004-10-07 20:38:51 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("return type mismatch in function declared to return %s",
|
|
|
|
format_type_be(rettype)),
|
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
|
|
|
errdetail("Final statement returns too many columns.")));
|
2020-01-08 17:07:53 +01:00
|
|
|
attr = TupleDescAttr(rettupdesc, colindex - 1);
|
|
|
|
if (attr->attisdropped && insertDroppedCols)
|
2009-12-14 03:15:54 +01:00
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
Expr *null_expr;
|
2009-12-14 03:15:54 +01:00
|
|
|
|
|
|
|
/* The type of the null we insert isn't important */
|
|
|
|
null_expr = (Expr *) makeConst(INT4OID,
|
|
|
|
-1,
|
2011-03-26 01:10:42 +01:00
|
|
|
InvalidOid,
|
2009-12-14 03:15:54 +01:00
|
|
|
sizeof(int32),
|
|
|
|
(Datum) 0,
|
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
|
|
|
true, /* isnull */
|
2009-12-14 03:15:54 +01:00
|
|
|
true /* byval */ );
|
2020-01-08 17:07:53 +01:00
|
|
|
upper_tlist = lappend(upper_tlist,
|
|
|
|
makeTargetEntry(null_expr,
|
|
|
|
list_length(upper_tlist) + 1,
|
|
|
|
NULL,
|
|
|
|
false));
|
|
|
|
upper_tlist_nontrivial = true;
|
2009-12-14 03:15:54 +01:00
|
|
|
}
|
2004-10-07 20:38:51 +02:00
|
|
|
} while (attr->attisdropped);
|
2005-04-01 00:46:33 +02:00
|
|
|
tuplogcols++;
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2020-01-08 17:07:53 +01:00
|
|
|
if (!coerce_fn_result_column(tle,
|
|
|
|
attr->atttypid, attr->atttypmod,
|
|
|
|
tlist_is_modifiable,
|
|
|
|
&upper_tlist,
|
|
|
|
&upper_tlist_nontrivial))
|
2004-10-07 20:38:51 +02:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("return type mismatch in function declared to return %s",
|
|
|
|
format_type_be(rettype)),
|
2008-10-31 20:37:56 +01:00
|
|
|
errdetail("Final statement returns %s instead of %s at column %d.",
|
2020-01-08 17:07:53 +01:00
|
|
|
format_type_be(exprType((Node *) tle->expr)),
|
|
|
|
format_type_be(attr->atttypid),
|
2005-04-01 00:46:33 +02:00
|
|
|
tuplogcols)));
|
2004-10-07 20:38:51 +02:00
|
|
|
}
|
|
|
|
|
2020-01-08 17:07:53 +01:00
|
|
|
/* remaining columns in rettupdesc had better all be dropped */
|
2009-12-14 03:15:54 +01:00
|
|
|
for (colindex++; colindex <= tupnatts; colindex++)
|
2004-10-07 20:38:51 +02:00
|
|
|
{
|
2020-01-08 17:07:53 +01:00
|
|
|
if (!TupleDescAttr(rettupdesc, colindex - 1)->attisdropped)
|
2009-12-14 03:15:54 +01:00
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
|
|
|
errmsg("return type mismatch in function declared to return %s",
|
|
|
|
format_type_be(rettype)),
|
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
|
|
|
errdetail("Final statement returns too few columns.")));
|
2020-01-08 17:07:53 +01:00
|
|
|
if (insertDroppedCols)
|
2009-12-14 03:15:54 +01:00
|
|
|
{
|
2010-02-26 03:01:40 +01:00
|
|
|
Expr *null_expr;
|
2009-12-14 03:15:54 +01:00
|
|
|
|
|
|
|
/* The type of the null we insert isn't important */
|
|
|
|
null_expr = (Expr *) makeConst(INT4OID,
|
|
|
|
-1,
|
2011-03-26 01:10:42 +01:00
|
|
|
InvalidOid,
|
2009-12-14 03:15:54 +01:00
|
|
|
sizeof(int32),
|
|
|
|
(Datum) 0,
|
2010-02-26 03:01:40 +01:00
|
|
|
true, /* isnull */
|
2009-12-14 03:15:54 +01:00
|
|
|
true /* byval */ );
|
2020-01-08 17:07:53 +01:00
|
|
|
upper_tlist = lappend(upper_tlist,
|
|
|
|
makeTargetEntry(null_expr,
|
|
|
|
list_length(upper_tlist) + 1,
|
|
|
|
NULL,
|
|
|
|
false));
|
|
|
|
upper_tlist_nontrivial = true;
|
2009-12-14 03:15:54 +01:00
|
|
|
}
|
2004-10-07 20:38:51 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Report that we are returning entire tuple result */
|
2020-01-08 17:07:53 +01:00
|
|
|
is_tuple_result = true;
|
2004-10-07 20:38:51 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ereport(ERROR,
|
|
|
|
(errcode(ERRCODE_INVALID_FUNCTION_DEFINITION),
|
2005-10-15 04:49:52 +02:00
|
|
|
errmsg("return type %s is not supported for SQL functions",
|
|
|
|
format_type_be(rettype))));
|
2004-10-07 20:38:51 +02:00
|
|
|
|
2020-01-08 17:07:53 +01:00
|
|
|
tlist_coercion_finished:
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If necessary, modify the final Query by injecting an extra Query level
|
|
|
|
* that just performs a projection. (It'd be dubious to do this to a
|
|
|
|
* non-SELECT query, but we never have to; RETURNING lists can always be
|
|
|
|
* modified in-place.)
|
|
|
|
*/
|
|
|
|
if (upper_tlist_nontrivial)
|
|
|
|
{
|
|
|
|
Query *newquery;
|
|
|
|
List *colnames;
|
|
|
|
RangeTblEntry *rte;
|
|
|
|
RangeTblRef *rtr;
|
|
|
|
|
|
|
|
Assert(parse->commandType == CMD_SELECT);
|
|
|
|
|
|
|
|
/* Most of the upper Query struct can be left as zeroes/nulls */
|
|
|
|
newquery = makeNode(Query);
|
|
|
|
newquery->commandType = CMD_SELECT;
|
|
|
|
newquery->querySource = parse->querySource;
|
|
|
|
newquery->canSetTag = true;
|
|
|
|
newquery->targetList = upper_tlist;
|
|
|
|
|
|
|
|
/* We need a moderately realistic colnames list for the subquery RTE */
|
|
|
|
colnames = NIL;
|
|
|
|
foreach(lc, parse->targetList)
|
|
|
|
{
|
|
|
|
TargetEntry *tle = (TargetEntry *) lfirst(lc);
|
|
|
|
|
|
|
|
if (tle->resjunk)
|
|
|
|
continue;
|
|
|
|
colnames = lappend(colnames,
|
|
|
|
makeString(tle->resname ? tle->resname : ""));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Build a suitable RTE for the subquery */
|
|
|
|
rte = makeNode(RangeTblEntry);
|
|
|
|
rte->rtekind = RTE_SUBQUERY;
|
|
|
|
rte->subquery = parse;
|
|
|
|
rte->eref = rte->alias = makeAlias("*SELECT*", colnames);
|
|
|
|
rte->lateral = false;
|
|
|
|
rte->inh = false;
|
|
|
|
rte->inFromCl = true;
|
|
|
|
newquery->rtable = list_make1(rte);
|
|
|
|
|
|
|
|
rtr = makeNode(RangeTblRef);
|
|
|
|
rtr->rtindex = 1;
|
|
|
|
newquery->jointree = makeFromExpr(list_make1(rtr), NULL);
|
|
|
|
|
|
|
|
/* Replace original query in the correct element of the query list */
|
|
|
|
lfirst(parse_cell) = newquery;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return tlist (possibly modified) if requested */
|
|
|
|
if (resultTargetList)
|
|
|
|
*resultTargetList = upper_tlist;
|
|
|
|
|
|
|
|
return is_tuple_result;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Process one function result column for check_sql_fn_retval
|
|
|
|
*
|
|
|
|
* Coerce the output value to the required type/typmod, and add a column
|
|
|
|
* to *upper_tlist for it. Set *upper_tlist_nontrivial to true if we
|
|
|
|
* add an upper tlist item that's not just a Var.
|
|
|
|
*
|
|
|
|
* Returns true if OK, false if could not coerce to required type
|
|
|
|
* (in which case, no changes have been made)
|
|
|
|
*/
|
|
|
|
static bool
|
|
|
|
coerce_fn_result_column(TargetEntry *src_tle,
|
|
|
|
Oid res_type,
|
|
|
|
int32 res_typmod,
|
|
|
|
bool tlist_is_modifiable,
|
|
|
|
List **upper_tlist,
|
|
|
|
bool *upper_tlist_nontrivial)
|
|
|
|
{
|
|
|
|
TargetEntry *new_tle;
|
|
|
|
Expr *new_tle_expr;
|
|
|
|
Node *cast_result;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the TLE has a sortgroupref marking, don't change it, as it probably
|
|
|
|
* is referenced by ORDER BY, DISTINCT, etc, and changing its type would
|
|
|
|
* break query semantics. Otherwise, it's safe to modify in-place unless
|
|
|
|
* the query as a whole has issues with that.
|
|
|
|
*/
|
|
|
|
if (tlist_is_modifiable && src_tle->ressortgroupref == 0)
|
|
|
|
{
|
|
|
|
/* OK to modify src_tle in place, if necessary */
|
|
|
|
cast_result = coerce_to_target_type(NULL,
|
|
|
|
(Node *) src_tle->expr,
|
|
|
|
exprType((Node *) src_tle->expr),
|
|
|
|
res_type, res_typmod,
|
|
|
|
COERCION_ASSIGNMENT,
|
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
-1);
|
|
|
|
if (cast_result == NULL)
|
|
|
|
return false;
|
2020-04-14 23:30:13 +02:00
|
|
|
assign_expr_collations(NULL, cast_result);
|
2020-01-08 17:07:53 +01:00
|
|
|
src_tle->expr = (Expr *) cast_result;
|
|
|
|
/* Make a Var referencing the possibly-modified TLE */
|
|
|
|
new_tle_expr = (Expr *) makeVarFromTargetEntry(1, src_tle);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Any casting must happen in the upper tlist */
|
|
|
|
Var *var = makeVarFromTargetEntry(1, src_tle);
|
|
|
|
|
|
|
|
cast_result = coerce_to_target_type(NULL,
|
|
|
|
(Node *) var,
|
|
|
|
var->vartype,
|
|
|
|
res_type, res_typmod,
|
|
|
|
COERCION_ASSIGNMENT,
|
|
|
|
COERCE_IMPLICIT_CAST,
|
|
|
|
-1);
|
|
|
|
if (cast_result == NULL)
|
|
|
|
return false;
|
2020-04-14 23:30:13 +02:00
|
|
|
assign_expr_collations(NULL, cast_result);
|
2020-01-08 17:07:53 +01:00
|
|
|
/* Did the coercion actually do anything? */
|
|
|
|
if (cast_result != (Node *) var)
|
|
|
|
*upper_tlist_nontrivial = true;
|
|
|
|
new_tle_expr = (Expr *) cast_result;
|
|
|
|
}
|
|
|
|
new_tle = makeTargetEntry(new_tle_expr,
|
|
|
|
list_length(*upper_tlist) + 1,
|
|
|
|
src_tle->resname, false);
|
|
|
|
*upper_tlist = lappend(*upper_tlist, new_tle);
|
|
|
|
return true;
|
2004-10-07 20:38:51 +02:00
|
|
|
}
|
2008-10-31 20:37:56 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* CreateSQLFunctionDestReceiver -- create a suitable DestReceiver object
|
|
|
|
*/
|
|
|
|
DestReceiver *
|
|
|
|
CreateSQLFunctionDestReceiver(void)
|
|
|
|
{
|
|
|
|
DR_sqlfunction *self = (DR_sqlfunction *) palloc0(sizeof(DR_sqlfunction));
|
|
|
|
|
|
|
|
self->pub.receiveSlot = sqlfunction_receive;
|
|
|
|
self->pub.rStartup = sqlfunction_startup;
|
|
|
|
self->pub.rShutdown = sqlfunction_shutdown;
|
|
|
|
self->pub.rDestroy = sqlfunction_destroy;
|
|
|
|
self->pub.mydest = DestSQLFunction;
|
|
|
|
|
2008-11-30 21:51:25 +01:00
|
|
|
/* private fields will be set by postquel_start */
|
|
|
|
|
2008-10-31 20:37:56 +01:00
|
|
|
return (DestReceiver *) self;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sqlfunction_startup --- executor startup
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sqlfunction_startup(DestReceiver *self, int operation, TupleDesc typeinfo)
|
|
|
|
{
|
|
|
|
/* no-op */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sqlfunction_receive --- receive one tuple
|
|
|
|
*/
|
2016-06-06 20:52:58 +02:00
|
|
|
static bool
|
2008-10-31 20:37:56 +01:00
|
|
|
sqlfunction_receive(TupleTableSlot *slot, DestReceiver *self)
|
|
|
|
{
|
|
|
|
DR_sqlfunction *myState = (DR_sqlfunction *) self;
|
|
|
|
|
|
|
|
/* Filter tuple as needed */
|
|
|
|
slot = ExecFilterJunk(myState->filter, slot);
|
|
|
|
|
|
|
|
/* Store the filtered tuple into the tuplestore */
|
|
|
|
tuplestore_puttupleslot(myState->tstore, slot);
|
2016-06-06 20:52:58 +02:00
|
|
|
|
|
|
|
return true;
|
2008-10-31 20:37:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sqlfunction_shutdown --- executor end
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sqlfunction_shutdown(DestReceiver *self)
|
|
|
|
{
|
|
|
|
/* no-op */
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* sqlfunction_destroy --- release DestReceiver object
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
sqlfunction_destroy(DestReceiver *self)
|
|
|
|
{
|
|
|
|
pfree(self);
|
|
|
|
}
|