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
|
|
|
*
|
2015-12-30 00:50:35 +01:00
|
|
|
* The rewriter's rewriteTargetListIU and rewriteTargetListUD routines
|
|
|
|
* also do preprocessing of the targetlist. The division of labor between
|
|
|
|
* here and there is partially historical, but it's not entirely arbitrary.
|
|
|
|
* In particular, consider an UPDATE across an inheritance tree. What the
|
|
|
|
* rewriter does need be done only once (because it depends only on the
|
|
|
|
* properties of the parent relation). What's done here has to be done over
|
|
|
|
* again for each child relation, because it depends on the column list of
|
|
|
|
* the child, which might have more columns and/or a different column order
|
|
|
|
* than the parent.
|
|
|
|
*
|
|
|
|
* The fact that rewriteTargetListIU sorts non-resjunk tlist entries by column
|
|
|
|
* position, which expand_targetlist depends on, violates the above comment
|
|
|
|
* because the sorting is only valid for the parent relation. In inherited
|
|
|
|
* UPDATE cases, adjust_inherited_tlist runs in between to take care of fixing
|
|
|
|
* the tlists for child tables to keep expand_targetlist happy. We do it like
|
|
|
|
* that because it's faster in typical non-inherited cases.
|
1999-10-31 01:06:32 +02:00
|
|
|
*
|
1996-07-09 08:22:35 +02:00
|
|
|
*
|
2016-01-02 19:33:40 +01:00
|
|
|
* Portions Copyright (c) 1996-2016, 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"
|
2016-03-10 21:52:58 +01:00
|
|
|
#include "optimizer/var.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);
|
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);
|
|
|
|
}
|
2015-04-22 17:29:35 +02:00
|
|
|
|
|
|
|
/* If parent of inheritance tree, always fetch the tableoid too. */
|
|
|
|
if (rc->isParent)
|
|
|
|
{
|
|
|
|
var = makeVar(rc->rti,
|
|
|
|
TableOidAttributeNumber,
|
|
|
|
OIDOID,
|
|
|
|
-1,
|
|
|
|
InvalidOid,
|
|
|
|
0);
|
|
|
|
snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId);
|
|
|
|
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,
|
2016-03-10 21:52:58 +01:00
|
|
|
PVC_RECURSE_AGGREGATES |
|
2016-03-10 22:23:40 +01:00
|
|
|
PVC_RECURSE_WINDOWFUNCS |
|
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
|
|
|
}
|
|
|
|
|
Add support for INSERT ... ON CONFLICT DO NOTHING/UPDATE.
The newly added ON CONFLICT clause allows to specify an alternative to
raising a unique or exclusion constraint violation error when inserting.
ON CONFLICT refers to constraints that can either be specified using a
inference clause (by specifying the columns of a unique constraint) or
by naming a unique or exclusion constraint. DO NOTHING avoids the
constraint violation, without touching the pre-existing row. DO UPDATE
SET ... [WHERE ...] updates the pre-existing tuple, and has access to
both the tuple proposed for insertion and the existing tuple; the
optional WHERE clause can be used to prevent an update from being
executed. The UPDATE SET and WHERE clauses have access to the tuple
proposed for insertion using the "magic" EXCLUDED alias, and to the
pre-existing tuple using the table name or its alias.
This feature is often referred to as upsert.
This is implemented using a new infrastructure called "speculative
insertion". It is an optimistic variant of regular insertion that first
does a pre-check for existing tuples and then attempts an insert. If a
violating tuple was inserted concurrently, the speculatively inserted
tuple is deleted and a new attempt is made. If the pre-check finds a
matching tuple the alternative DO NOTHING or DO UPDATE action is taken.
If the insertion succeeds without detecting a conflict, the tuple is
deemed inserted.
To handle the possible ambiguity between the excluded alias and a table
named excluded, and for convenience with long relation names, INSERT
INTO now can alias its target table.
Bumps catversion as stored rules change.
Author: Peter Geoghegan, with significant contributions from Heikki
Linnakangas and Andres Freund. Testing infrastructure by Jeff Janes.
Reviewed-By: Heikki Linnakangas, Andres Freund, Robert Haas, Simon Riggs,
Dean Rasheed, Stephen Frost and many others.
2015-05-08 05:31:36 +02:00
|
|
|
/*
|
|
|
|
* preprocess_onconflict_targetlist
|
|
|
|
* Process ON CONFLICT SET targetlist.
|
|
|
|
*
|
|
|
|
* Returns the new targetlist.
|
|
|
|
*/
|
|
|
|
List *
|
|
|
|
preprocess_onconflict_targetlist(List *tlist, int result_relation, List *range_table)
|
|
|
|
{
|
|
|
|
return expand_targetlist(tlist, CMD_UPDATE, result_relation, range_table);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
}
|