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
|
|
|
|
* each attribute of the target relation in the correct order. For all query
|
|
|
|
* types, we may need to add junk tlist entries for Vars used in the RETURNING
|
|
|
|
* list and row ID information needed for EvalPlanQual checking.
|
|
|
|
*
|
|
|
|
* 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
|
|
|
*
|
2011-01-01 19:18:15 +01:00
|
|
|
* Portions Copyright (c) 1996-2011, 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"
|
2005-03-18 00:45:09 +01:00
|
|
|
#include "optimizer/subselect.h"
|
2006-08-12 04:52:06 +02:00
|
|
|
#include "optimizer/tlist.h"
|
|
|
|
#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
|
2011-01-13 02:47:02 +01: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
|
|
|
|
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->markType != ROW_MARK_COPY)
|
|
|
|
{
|
|
|
|
/* It's a regular table, so fetch its 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
|
|
|
}
|
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
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Not a table, so we 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,
|
|
|
|
0);
|
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
|
2006-10-04 02:30:14 +02:00
|
|
|
* to make these Vars available for the RETURNING calculation. Vars that
|
|
|
|
* 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,
|
|
|
|
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
|
|
|
|
* since that might not exist anymore. It does not really matter
|
|
|
|
* what we claim the type is, since NULL is NULL --- its
|
|
|
|
* representation is datatype-independent. This could perhaps
|
|
|
|
* 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
|
|
|
|
* real attribute. (Note: although the rewriter already did such
|
|
|
|
* 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;
|
|
|
|
}
|