1996-07-09 08:22:35 +02:00
|
|
|
/*-------------------------------------------------------------------------
|
|
|
|
*
|
1999-02-14 00:22:53 +01:00
|
|
|
* preptlist.c
|
1997-09-07 07:04:48 +02:00
|
|
|
* Routines to preprocess the parse tree target list
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2010-10-10 19:43:33 +02:00
|
|
|
* For INSERT and UPDATE queries, the targetlist must contain an entry for
|
2014-05-06 18:12:18 +02:00
|
|
|
* each attribute of the target relation in the correct order. For all query
|
2010-10-10 19:43:33 +02:00
|
|
|
* types, we may need to add junk tlist entries for Vars used in the RETURNING
|
2013-03-10 19:14:53 +01:00
|
|
|
* list and row ID information needed for SELECT FOR UPDATE locking and/or
|
|
|
|
* EvalPlanQual checking.
|
2010-10-10 19:43:33 +02:00
|
|
|
*
|
|
|
|
* NOTE: the rewriter's rewriteTargetListIU and rewriteTargetListUD
|
|
|
|
* routines also do preprocessing of the targetlist. The division of labor
|
|
|
|
* between here and there is a bit arbitrary and historical.
|
1999-10-31 01:06:32 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2015-01-06 17:43:47 +01:00
|
|
|
* Portions Copyright (c) 1996-2015, 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/optimizer/prep/preptlist.c
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*-------------------------------------------------------------------------
|
|
|
|
*/
|
1999-10-31 01:06:32 +02:00
|
|
|
|
1996-07-09 08:22:35 +02:00
|
|
|
#include "postgres.h"
|
|
|
|
|
1999-10-31 01:06:32 +02:00
|
|
|
#include "access/heapam.h"
|
2008-05-12 02:00:54 +02:00
|
|
|
#include "access/sysattr.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
#include "nodes/makefuncs.h"
|
|
|
|
#include "optimizer/prep.h"
|
2006-08-12 04:52:06 +02:00
|
|
|
#include "optimizer/tlist.h"
|
1999-07-16 07:00:38 +02:00
|
|
|
#include "parser/parsetree.h"
|
2002-09-01 00:10:48 +02:00
|
|
|
#include "parser/parse_coerce.h"
|
2008-06-19 02:46:06 +02:00
|
|
|
#include "utils/rel.h"
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-10-31 01:06:32 +02:00
|
|
|
|
|
|
|
static List *expand_targetlist(List *tlist, int command_type,
|
2000-04-12 19:17:23 +02:00
|
|
|
Index result_relation, List *range_table);
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
|
|
|
|
/*
|
1999-02-14 00:22:53 +01:00
|
|
|
* preprocess_targetlist
|
1997-09-07 07:04:48 +02:00
|
|
|
* Driver for preprocessing the parse tree targetlist.
|
|
|
|
*
|
|
|
|
* Returns the new targetlist.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1998-02-26 05:46:47 +01:00
|
|
|
List *
|
2005-06-06 00:32:58 +02:00
|
|
|
preprocess_targetlist(PlannerInfo *root, List *tlist)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
2005-10-15 04:49:52 +02:00
|
|
|
Query *parse = root->parse;
|
|
|
|
int result_relation = parse->resultRelation;
|
|
|
|
List *range_table = parse->rtable;
|
|
|
|
CmdType command_type = parse->commandType;
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
ListCell *lc;
|
2005-03-18 00:45:09 +01:00
|
|
|
|
2000-10-05 21:11:39 +02:00
|
|
|
/*
|
2001-03-22 05:01:46 +01:00
|
|
|
* Sanity check: if there is a result relation, it'd better be a real
|
|
|
|
* relation not a subquery. Else parser or rewriter messed up.
|
2000-10-05 21:11:39 +02:00
|
|
|
*/
|
|
|
|
if (result_relation)
|
|
|
|
{
|
|
|
|
RangeTblEntry *rte = rt_fetch(result_relation, range_table);
|
|
|
|
|
|
|
|
if (rte->subquery != NULL || rte->relid == InvalidOid)
|
2003-07-25 02:01:09 +02:00
|
|
|
elog(ERROR, "subquery cannot be result relation");
|
2000-10-05 21:11:39 +02:00
|
|
|
}
|
2000-04-12 19:17:23 +02:00
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
2008-11-02 02:45:28 +01:00
|
|
|
* for heap_form_tuple to work, the targetlist must match the exact order
|
2005-11-22 19:17:34 +01:00
|
|
|
* of the attributes. We also need to fill in any missing attributes. -ay
|
|
|
|
* 10/94
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
1999-10-31 01:06:32 +02:00
|
|
|
if (command_type == CMD_INSERT || command_type == CMD_UPDATE)
|
|
|
|
tlist = expand_targetlist(tlist, command_type,
|
|
|
|
result_relation, range_table);
|
|
|
|
|
2005-03-18 00:45:09 +01:00
|
|
|
/*
|
2010-02-26 03:01:40 +01:00
|
|
|
* Add necessary junk columns for rowmarked rels. These values are needed
|
|
|
|
* for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual
|
2014-05-06 18:12:18 +02:00
|
|
|
* rechecking. See comments for PlanRowMark in plannodes.h.
|
2005-03-18 00:45:09 +01:00
|
|
|
*/
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
foreach(lc, root->rowMarks)
|
2005-03-18 00:45:09 +01:00
|
|
|
{
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
PlanRowMark *rc = (PlanRowMark *) lfirst(lc);
|
|
|
|
Var *var;
|
|
|
|
char resname[32];
|
|
|
|
TargetEntry *tle;
|
2005-03-18 00:45:09 +01:00
|
|
|
|
2011-01-13 02:47:02 +01:00
|
|
|
/* child rels use the same junk attrs as their parents */
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
if (rc->rti != rc->prti)
|
|
|
|
continue;
|
2009-10-12 20:10:51 +02:00
|
|
|
|
Improve representation of PlanRowMark.
This patch fixes two inadequacies of the PlanRowMark representation.
First, that the original LockingClauseStrength isn't stored (and cannot be
inferred for foreign tables, which always get ROW_MARK_COPY). Since some
PlanRowMarks are created out of whole cloth and don't actually have an
ancestral RowMarkClause, this requires adding a dummy LCS_NONE value to
enum LockingClauseStrength, which is fairly annoying but the alternatives
seem worse. This fix allows getting rid of the use of get_parse_rowmark()
in FDWs (as per the discussion around commits 462bd95705a0c23b and
8ec8760fc87ecde0), and it simplifies some things elsewhere.
Second, that the representation assumed that all child tables in an
inheritance hierarchy would use the same RowMarkType. That's true today
but will soon not be true. We add an "allMarkTypes" field that identifies
the union of mark types used in all a parent table's children, and use
that where appropriate (currently, only in preprocess_targetlist()).
In passing fix a couple of minor infelicities left over from the SKIP
LOCKED patch, notably that _outPlanRowMark still thought waitPolicy
is a bool.
Catversion bump is required because the numeric values of enum
LockingClauseStrength can appear in on-disk rules.
Extracted from a much larger patch to support foreign table inheritance;
it seemed worth breaking this out, since it's a separable concern.
Shigeru Hanada and Etsuro Fujita, somewhat modified by me
2015-03-15 23:41:47 +01:00
|
|
|
if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY))
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
{
|
Improve representation of PlanRowMark.
This patch fixes two inadequacies of the PlanRowMark representation.
First, that the original LockingClauseStrength isn't stored (and cannot be
inferred for foreign tables, which always get ROW_MARK_COPY). Since some
PlanRowMarks are created out of whole cloth and don't actually have an
ancestral RowMarkClause, this requires adding a dummy LCS_NONE value to
enum LockingClauseStrength, which is fairly annoying but the alternatives
seem worse. This fix allows getting rid of the use of get_parse_rowmark()
in FDWs (as per the discussion around commits 462bd95705a0c23b and
8ec8760fc87ecde0), and it simplifies some things elsewhere.
Second, that the representation assumed that all child tables in an
inheritance hierarchy would use the same RowMarkType. That's true today
but will soon not be true. We add an "allMarkTypes" field that identifies
the union of mark types used in all a parent table's children, and use
that where appropriate (currently, only in preprocess_targetlist()).
In passing fix a couple of minor infelicities left over from the SKIP
LOCKED patch, notably that _outPlanRowMark still thought waitPolicy
is a bool.
Catversion bump is required because the numeric values of enum
LockingClauseStrength can appear in on-disk rules.
Extracted from a much larger patch to support foreign table inheritance;
it seemed worth breaking this out, since it's a separable concern.
Shigeru Hanada and Etsuro Fujita, somewhat modified by me
2015-03-15 23:41:47 +01:00
|
|
|
/* Need to fetch TID */
|
2006-04-30 20:30:40 +02:00
|
|
|
var = makeVar(rc->rti,
|
2005-03-18 00:45:09 +01:00
|
|
|
SelfItemPointerAttributeNumber,
|
|
|
|
TIDOID,
|
|
|
|
-1,
|
2011-02-08 22:04:18 +01:00
|
|
|
InvalidOid,
|
2005-03-18 00:45:09 +01:00
|
|
|
0);
|
2011-02-10 05:27:07 +01:00
|
|
|
snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId);
|
2005-04-06 18:34:07 +02:00
|
|
|
tle = makeTargetEntry((Expr *) var,
|
|
|
|
list_length(tlist) + 1,
|
2009-10-12 20:10:51 +02:00
|
|
|
pstrdup(resname),
|
2005-04-06 18:34:07 +02:00
|
|
|
true);
|
|
|
|
tlist = lappend(tlist, tle);
|
2008-11-15 20:43:47 +01:00
|
|
|
|
|
|
|
/* if parent of inheritance tree, need the tableoid too */
|
|
|
|
if (rc->isParent)
|
|
|
|
{
|
|
|
|
var = makeVar(rc->rti,
|
|
|
|
TableOidAttributeNumber,
|
|
|
|
OIDOID,
|
|
|
|
-1,
|
2011-02-08 22:04:18 +01:00
|
|
|
InvalidOid,
|
2008-11-15 20:43:47 +01:00
|
|
|
0);
|
2011-02-10 05:27:07 +01:00
|
|
|
snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
|
2008-11-15 20:43:47 +01:00
|
|
|
tle = makeTargetEntry((Expr *) var,
|
|
|
|
list_length(tlist) + 1,
|
2009-10-12 20:10:51 +02:00
|
|
|
pstrdup(resname),
|
2008-11-15 20:43:47 +01:00
|
|
|
true);
|
|
|
|
tlist = lappend(tlist, tle);
|
|
|
|
}
|
2005-03-18 00:45:09 +01:00
|
|
|
}
|
Improve representation of PlanRowMark.
This patch fixes two inadequacies of the PlanRowMark representation.
First, that the original LockingClauseStrength isn't stored (and cannot be
inferred for foreign tables, which always get ROW_MARK_COPY). Since some
PlanRowMarks are created out of whole cloth and don't actually have an
ancestral RowMarkClause, this requires adding a dummy LCS_NONE value to
enum LockingClauseStrength, which is fairly annoying but the alternatives
seem worse. This fix allows getting rid of the use of get_parse_rowmark()
in FDWs (as per the discussion around commits 462bd95705a0c23b and
8ec8760fc87ecde0), and it simplifies some things elsewhere.
Second, that the representation assumed that all child tables in an
inheritance hierarchy would use the same RowMarkType. That's true today
but will soon not be true. We add an "allMarkTypes" field that identifies
the union of mark types used in all a parent table's children, and use
that where appropriate (currently, only in preprocess_targetlist()).
In passing fix a couple of minor infelicities left over from the SKIP
LOCKED patch, notably that _outPlanRowMark still thought waitPolicy
is a bool.
Catversion bump is required because the numeric values of enum
LockingClauseStrength can appear in on-disk rules.
Extracted from a much larger patch to support foreign table inheritance;
it seemed worth breaking this out, since it's a separable concern.
Shigeru Hanada and Etsuro Fujita, somewhat modified by me
2015-03-15 23:41:47 +01:00
|
|
|
if (rc->allMarkTypes & (1 << ROW_MARK_COPY))
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
{
|
Improve representation of PlanRowMark.
This patch fixes two inadequacies of the PlanRowMark representation.
First, that the original LockingClauseStrength isn't stored (and cannot be
inferred for foreign tables, which always get ROW_MARK_COPY). Since some
PlanRowMarks are created out of whole cloth and don't actually have an
ancestral RowMarkClause, this requires adding a dummy LCS_NONE value to
enum LockingClauseStrength, which is fairly annoying but the alternatives
seem worse. This fix allows getting rid of the use of get_parse_rowmark()
in FDWs (as per the discussion around commits 462bd95705a0c23b and
8ec8760fc87ecde0), and it simplifies some things elsewhere.
Second, that the representation assumed that all child tables in an
inheritance hierarchy would use the same RowMarkType. That's true today
but will soon not be true. We add an "allMarkTypes" field that identifies
the union of mark types used in all a parent table's children, and use
that where appropriate (currently, only in preprocess_targetlist()).
In passing fix a couple of minor infelicities left over from the SKIP
LOCKED patch, notably that _outPlanRowMark still thought waitPolicy
is a bool.
Catversion bump is required because the numeric values of enum
LockingClauseStrength can appear in on-disk rules.
Extracted from a much larger patch to support foreign table inheritance;
it seemed worth breaking this out, since it's a separable concern.
Shigeru Hanada and Etsuro Fujita, somewhat modified by me
2015-03-15 23:41:47 +01:00
|
|
|
/* Need the whole row as a junk var */
|
2010-10-19 21:08:37 +02:00
|
|
|
var = makeWholeRowVar(rt_fetch(rc->rti, range_table),
|
|
|
|
rc->rti,
|
2011-11-28 04:27:24 +01:00
|
|
|
0,
|
|
|
|
false);
|
2011-02-10 05:27:07 +01:00
|
|
|
snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId);
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
tle = makeTargetEntry((Expr *) var,
|
|
|
|
list_length(tlist) + 1,
|
|
|
|
pstrdup(resname),
|
|
|
|
true);
|
|
|
|
tlist = lappend(tlist, tle);
|
|
|
|
}
|
2005-03-18 00:45:09 +01:00
|
|
|
}
|
|
|
|
|
2006-08-12 04:52:06 +02:00
|
|
|
/*
|
|
|
|
* If the query has a RETURNING list, add resjunk entries for any Vars
|
|
|
|
* used in RETURNING that belong to other relations. We need to do this
|
2014-05-06 18:12:18 +02:00
|
|
|
* to make these Vars available for the RETURNING calculation. Vars that
|
2006-10-04 02:30:14 +02:00
|
|
|
* belong to the result rel don't need to be added, because they will be
|
|
|
|
* made to refer to the actual heap tuple.
|
2006-08-12 04:52:06 +02:00
|
|
|
*/
|
|
|
|
if (parse->returningList && list_length(parse->rtable) > 1)
|
|
|
|
{
|
2006-10-04 02:30:14 +02:00
|
|
|
List *vars;
|
2006-08-12 04:52:06 +02:00
|
|
|
ListCell *l;
|
|
|
|
|
2009-04-19 21:46:33 +02:00
|
|
|
vars = pull_var_clause((Node *) parse->returningList,
|
Avoid listing ungrouped Vars in the targetlist of Agg-underneath-Window.
Regular aggregate functions in combination with, or within the arguments
of, window functions are OK per spec; they have the semantics that the
aggregate output rows are computed and then we run the window functions
over that row set. (Thus, this combination is not really useful unless
there's a GROUP BY so that more than one aggregate output row is possible.)
The case without GROUP BY could fail, as recently reported by Jeff Davis,
because sloppy construction of the Agg node's targetlist resulted in extra
references to possibly-ungrouped Vars appearing outside the aggregate
function calls themselves. See the added regression test case for an
example.
Fixing this requires modifying the API of flatten_tlist and its underlying
function pull_var_clause. I chose to make pull_var_clause's API for
aggregates identical to what it was already doing for placeholders, since
the useful behaviors turn out to be the same (error, report node as-is, or
recurse into it). I also tightened the error checking in this area a bit:
if it was ever valid to see an uplevel Var, Aggref, or PlaceHolderVar here,
that was a long time ago, so complain instead of ignoring them.
Backpatch into 9.1. The failure exists in 8.4 and 9.0 as well, but seeing
that it only occurs in a basically-useless corner case, it doesn't seem
worth the risks of changing a function API in a minor release. There might
be third-party code using pull_var_clause.
2011-07-13 00:23:55 +02:00
|
|
|
PVC_RECURSE_AGGREGATES,
|
2009-04-19 21:46:33 +02:00
|
|
|
PVC_INCLUDE_PLACEHOLDERS);
|
2006-08-12 04:52:06 +02:00
|
|
|
foreach(l, vars)
|
|
|
|
{
|
|
|
|
Var *var = (Var *) lfirst(l);
|
|
|
|
TargetEntry *tle;
|
|
|
|
|
2008-10-21 22:42:53 +02:00
|
|
|
if (IsA(var, Var) &&
|
|
|
|
var->varno == result_relation)
|
2006-08-12 04:52:06 +02:00
|
|
|
continue; /* don't need it */
|
|
|
|
|
|
|
|
if (tlist_member((Node *) var, tlist))
|
|
|
|
continue; /* already got it */
|
|
|
|
|
|
|
|
tle = makeTargetEntry((Expr *) var,
|
|
|
|
list_length(tlist) + 1,
|
|
|
|
NULL,
|
|
|
|
true);
|
|
|
|
|
|
|
|
tlist = lappend(tlist, tle);
|
|
|
|
}
|
|
|
|
list_free(vars);
|
|
|
|
}
|
|
|
|
|
1999-10-31 01:06:32 +02:00
|
|
|
return tlist;
|
1996-07-09 08:22:35 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************************************
|
|
|
|
*
|
1997-09-07 07:04:48 +02:00
|
|
|
* TARGETLIST EXPANSION
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
|
|
|
*****************************************************************************/
|
|
|
|
|
1997-09-07 07:04:48 +02:00
|
|
|
/*
|
1999-02-14 00:22:53 +01:00
|
|
|
* expand_targetlist
|
1997-09-07 07:04:48 +02:00
|
|
|
* Given a target list as generated by the parser and a result relation,
|
2002-04-05 07:47:05 +02:00
|
|
|
* add targetlist entries for any missing attributes, and ensure the
|
|
|
|
* non-junk attributes appear in proper field order.
|
1996-07-09 08:22:35 +02:00
|
|
|
*/
|
1997-09-08 04:41:22 +02:00
|
|
|
static List *
|
1999-10-31 01:06:32 +02:00
|
|
|
expand_targetlist(List *tlist, int command_type,
|
|
|
|
Index result_relation, List *range_table)
|
1996-07-09 08:22:35 +02:00
|
|
|
{
|
1999-10-31 01:06:32 +02:00
|
|
|
List *new_tlist = NIL;
|
2004-05-26 06:41:50 +02:00
|
|
|
ListCell *tlist_item;
|
1999-10-31 01:06:32 +02:00
|
|
|
Relation rel;
|
|
|
|
int attrno,
|
2002-04-05 07:47:05 +02:00
|
|
|
numattrs;
|
1997-09-07 07:04:48 +02:00
|
|
|
|
2004-05-26 06:41:50 +02:00
|
|
|
tlist_item = list_head(tlist);
|
|
|
|
|
1999-10-31 01:06:32 +02:00
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The rewriter should have already ensured that the TLEs are in correct
|
|
|
|
* order; but we have to insert TLEs for any missing attributes.
|
2000-07-22 08:19:04 +02:00
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
* Scan the tuple description in the relation's relcache entry to make
|
|
|
|
* sure we have all the user attributes in the right order. We assume
|
|
|
|
* that the rewriter already acquired at least AccessShareLock on the
|
|
|
|
* relation, so we need no lock here.
|
1997-09-07 07:04:48 +02:00
|
|
|
*/
|
2005-05-23 05:01:14 +02:00
|
|
|
rel = heap_open(getrelid(result_relation, range_table), NoLock);
|
1997-09-07 07:04:48 +02:00
|
|
|
|
1999-10-31 01:06:32 +02:00
|
|
|
numattrs = RelationGetNumberOfAttributes(rel);
|
|
|
|
|
|
|
|
for (attrno = 1; attrno <= numattrs; attrno++)
|
|
|
|
{
|
2000-04-12 19:17:23 +02:00
|
|
|
Form_pg_attribute att_tup = rel->rd_att->attrs[attrno - 1];
|
|
|
|
TargetEntry *new_tle = NULL;
|
1999-08-21 05:49:17 +02:00
|
|
|
|
2004-05-26 06:41:50 +02:00
|
|
|
if (tlist_item != NULL)
|
1999-05-12 17:02:39 +02:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
|
1999-05-12 17:02:39 +02:00
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
if (!old_tle->resjunk && old_tle->resno == attrno)
|
1999-05-12 17:02:39 +02:00
|
|
|
{
|
2002-04-05 07:47:05 +02:00
|
|
|
new_tle = old_tle;
|
2004-05-26 06:41:50 +02:00
|
|
|
tlist_item = lnext(tlist_item);
|
1999-05-12 17:02:39 +02:00
|
|
|
}
|
|
|
|
}
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-10-31 01:06:32 +02:00
|
|
|
if (new_tle == NULL)
|
1999-05-29 03:48:06 +02:00
|
|
|
{
|
1999-10-31 01:06:32 +02:00
|
|
|
/*
|
|
|
|
* Didn't find a matching tlist entry, so make one.
|
|
|
|
*
|
2002-09-04 22:31:48 +02:00
|
|
|
* For INSERT, generate a NULL constant. (We assume the rewriter
|
2005-10-15 04:49:52 +02:00
|
|
|
* would have inserted any available default value.) Also, if the
|
|
|
|
* column isn't dropped, apply any domain constraints that might
|
|
|
|
* exist --- this is to catch domain NOT NULL.
|
1999-10-31 01:06:32 +02:00
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
* For UPDATE, generate a Var reference to the existing value of
|
|
|
|
* the attribute, so that it gets copied to the new tuple. But
|
2005-10-15 04:49:52 +02:00
|
|
|
* generate a NULL for dropped columns (we want to drop any old
|
|
|
|
* values).
|
2003-05-12 02:17:03 +02:00
|
|
|
*
|
2005-11-22 19:17:34 +01:00
|
|
|
* When generating a NULL constant for a dropped column, we label
|
|
|
|
* it INT4 (any other guaranteed-to-exist datatype would do as
|
|
|
|
* well). We can't label it with the dropped column's datatype
|
2014-05-06 18:12:18 +02:00
|
|
|
* since that might not exist anymore. It does not really matter
|
2005-11-22 19:17:34 +01:00
|
|
|
* what we claim the type is, since NULL is NULL --- its
|
2014-05-06 18:12:18 +02:00
|
|
|
* representation is datatype-independent. This could perhaps
|
2005-11-22 19:17:34 +01:00
|
|
|
* confuse code comparing the finished plan to the target
|
|
|
|
* relation, however.
|
1999-10-31 01:06:32 +02:00
|
|
|
*/
|
|
|
|
Oid atttype = att_tup->atttypid;
|
|
|
|
int32 atttypmod = att_tup->atttypmod;
|
2011-02-08 22:04:18 +01:00
|
|
|
Oid attcollation = att_tup->attcollation;
|
2001-11-02 21:23:02 +01:00
|
|
|
Node *new_expr;
|
1996-07-09 08:22:35 +02:00
|
|
|
|
1999-10-31 01:06:32 +02:00
|
|
|
switch (command_type)
|
|
|
|
{
|
|
|
|
case CMD_INSERT:
|
2002-09-01 00:10:48 +02:00
|
|
|
if (!att_tup->attisdropped)
|
2003-05-12 02:17:03 +02:00
|
|
|
{
|
|
|
|
new_expr = (Node *) makeConst(atttype,
|
2007-03-17 01:11:05 +01:00
|
|
|
-1,
|
2011-03-26 01:10:42 +01:00
|
|
|
attcollation,
|
2003-05-12 02:17:03 +02:00
|
|
|
att_tup->attlen,
|
|
|
|
(Datum) 0,
|
2003-08-04 02:43:34 +02:00
|
|
|
true, /* isnull */
|
2003-05-12 02:17:03 +02:00
|
|
|
att_tup->attbyval);
|
2003-02-03 22:15:45 +01:00
|
|
|
new_expr = coerce_to_domain(new_expr,
|
2006-04-06 00:11:58 +02:00
|
|
|
InvalidOid, -1,
|
2003-02-03 22:15:45 +01:00
|
|
|
atttype,
|
2004-06-16 03:27:00 +02:00
|
|
|
COERCE_IMPLICIT_CAST,
|
2008-08-29 01:09:48 +02:00
|
|
|
-1,
|
2004-11-06 18:46:38 +01:00
|
|
|
false,
|
2004-06-16 03:27:00 +02:00
|
|
|
false);
|
2003-05-12 02:17:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Insert NULL for dropped column */
|
|
|
|
new_expr = (Node *) makeConst(INT4OID,
|
2007-03-17 01:11:05 +01:00
|
|
|
-1,
|
2011-03-26 01:10:42 +01:00
|
|
|
InvalidOid,
|
2003-05-12 02:17:03 +02:00
|
|
|
sizeof(int32),
|
|
|
|
(Datum) 0,
|
2003-08-04 02:43:34 +02:00
|
|
|
true, /* isnull */
|
|
|
|
true /* byval */ );
|
2003-05-12 02:17:03 +02:00
|
|
|
}
|
2001-11-02 21:23:02 +01:00
|
|
|
break;
|
1999-10-31 01:06:32 +02:00
|
|
|
case CMD_UPDATE:
|
2003-05-12 02:17:03 +02:00
|
|
|
if (!att_tup->attisdropped)
|
|
|
|
{
|
2002-08-02 20:15:10 +02:00
|
|
|
new_expr = (Node *) makeVar(result_relation,
|
|
|
|
attrno,
|
|
|
|
atttype,
|
|
|
|
atttypmod,
|
2011-02-08 22:04:18 +01:00
|
|
|
attcollation,
|
2002-08-02 20:15:10 +02:00
|
|
|
0);
|
2003-05-12 02:17:03 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Insert NULL for dropped column */
|
|
|
|
new_expr = (Node *) makeConst(INT4OID,
|
2007-03-17 01:11:05 +01:00
|
|
|
-1,
|
2011-03-26 01:10:42 +01:00
|
|
|
InvalidOid,
|
2003-05-12 02:17:03 +02:00
|
|
|
sizeof(int32),
|
|
|
|
(Datum) 0,
|
2003-08-04 02:43:34 +02:00
|
|
|
true, /* isnull */
|
|
|
|
true /* byval */ );
|
2003-05-12 02:17:03 +02:00
|
|
|
}
|
2001-11-02 21:23:02 +01:00
|
|
|
break;
|
1999-10-31 01:06:32 +02:00
|
|
|
default:
|
2003-07-25 02:01:09 +02:00
|
|
|
elog(ERROR, "unrecognized command_type: %d",
|
|
|
|
(int) command_type);
|
2001-11-05 18:46:40 +01:00
|
|
|
new_expr = NULL; /* keep compiler quiet */
|
1999-10-31 01:06:32 +02:00
|
|
|
break;
|
|
|
|
}
|
2001-11-02 21:23:02 +01:00
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
new_tle = makeTargetEntry((Expr *) new_expr,
|
|
|
|
attrno,
|
2002-09-04 22:31:48 +02:00
|
|
|
pstrdup(NameStr(att_tup->attname)),
|
2005-04-06 18:34:07 +02:00
|
|
|
false);
|
1999-10-31 01:06:32 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
new_tlist = lappend(new_tlist, new_tle);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
2005-10-15 04:49:52 +02:00
|
|
|
* The remaining tlist entries should be resjunk; append them all to the
|
|
|
|
* end of the new tlist, making sure they have resnos higher than the last
|
2014-05-06 18:12:18 +02:00
|
|
|
* real attribute. (Note: although the rewriter already did such
|
2005-10-15 04:49:52 +02:00
|
|
|
* renumbering, we have to do it again here in case we are doing an UPDATE
|
|
|
|
* in a table with dropped columns, or an inheritance child table with
|
|
|
|
* extra columns.)
|
1999-10-31 01:06:32 +02:00
|
|
|
*/
|
2004-05-26 06:41:50 +02:00
|
|
|
while (tlist_item)
|
1999-10-31 01:06:32 +02:00
|
|
|
{
|
2004-05-26 06:41:50 +02:00
|
|
|
TargetEntry *old_tle = (TargetEntry *) lfirst(tlist_item);
|
1999-10-31 01:06:32 +02:00
|
|
|
|
2005-04-06 18:34:07 +02:00
|
|
|
if (!old_tle->resjunk)
|
2003-07-25 02:01:09 +02:00
|
|
|
elog(ERROR, "targetlist is not sorted correctly");
|
2002-04-05 07:47:05 +02:00
|
|
|
/* Get the resno right, but don't copy unnecessarily */
|
2005-04-06 18:34:07 +02:00
|
|
|
if (old_tle->resno != attrno)
|
1999-10-31 01:06:32 +02:00
|
|
|
{
|
2005-04-06 18:34:07 +02:00
|
|
|
old_tle = flatCopyTargetEntry(old_tle);
|
|
|
|
old_tle->resno = attrno;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
2002-04-05 07:47:05 +02:00
|
|
|
new_tlist = lappend(new_tlist, old_tle);
|
|
|
|
attrno++;
|
2004-05-26 06:41:50 +02:00
|
|
|
tlist_item = lnext(tlist_item);
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
|
|
|
|
2005-05-23 05:01:14 +02:00
|
|
|
heap_close(rel, NoLock);
|
1999-10-31 01:06:32 +02:00
|
|
|
|
|
|
|
return new_tlist;
|
1997-09-07 07:04:48 +02:00
|
|
|
}
|
Re-implement EvalPlanQual processing to improve its performance and eliminate
a lot of strange behaviors that occurred in join cases. We now identify the
"current" row for every joined relation in UPDATE, DELETE, and SELECT FOR
UPDATE/SHARE queries. If an EvalPlanQual recheck is necessary, we jam the
appropriate row into each scan node in the rechecking plan, forcing it to emit
only that one row. The former behavior could rescan the whole of each joined
relation for each recheck, which was terrible for performance, and what's much
worse could result in duplicated output tuples.
Also, the original implementation of EvalPlanQual could not re-use the recheck
execution tree --- it had to go through a full executor init and shutdown for
every row to be tested. To avoid this overhead, I've associated a special
runtime Param with each LockRows or ModifyTable plan node, and arranged to
make every scan node below such a node depend on that Param. Thus, by
signaling a change in that Param, the EPQ machinery can just rescan the
already-built test plan.
This patch also adds a prohibition on set-returning functions in the
targetlist of SELECT FOR UPDATE/SHARE. This is needed to avoid the
duplicate-output-tuple problem. It seems fairly reasonable since the
other restrictions on SELECT FOR UPDATE are meant to ensure that there
is a unique correspondence between source tuples and result tuples,
which an output SRF destroys as much as anything else does.
2009-10-26 03:26:45 +01:00
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Locate PlanRowMark for given RT index, or return NULL if none
|
|
|
|
*
|
|
|
|
* This probably ought to be elsewhere, but there's no very good place
|
|
|
|
*/
|
|
|
|
PlanRowMark *
|
|
|
|
get_plan_rowmark(List *rowmarks, Index rtindex)
|
|
|
|
{
|
|
|
|
ListCell *l;
|
|
|
|
|
|
|
|
foreach(l, rowmarks)
|
|
|
|
{
|
|
|
|
PlanRowMark *rc = (PlanRowMark *) lfirst(l);
|
|
|
|
|
|
|
|
if (rc->rti == rtindex)
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|