mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-12-27 08:39:28 +08:00
Fix a couple of places in execMain that erroneously assumed that SELECT FOR
UPDATE/SHARE couldn't occur as a subquery in a query with a non-SELECT top-level operation. Symptoms included outright failure (as in report from Mark Mielke) and silently neglecting to take the requested row locks. Back-patch to 8.3, because the visible failure in the INSERT ... SELECT case is a regression from 8.2. I'm a bit hesitant to back-patch further given the lack of field complaints.
This commit is contained in:
parent
819b49a6e1
commit
f593f62336
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* IDENTIFICATION
|
* IDENTIFICATION
|
||||||
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.305 2008/03/28 00:21:55 tgl Exp $
|
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.306 2008/04/21 03:49:45 tgl Exp $
|
||||||
*
|
*
|
||||||
*-------------------------------------------------------------------------
|
*-------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
@ -754,6 +754,16 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|||||||
*/
|
*/
|
||||||
estate->es_junkFilter =
|
estate->es_junkFilter =
|
||||||
estate->es_result_relation_info->ri_junkFilter;
|
estate->es_result_relation_info->ri_junkFilter;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We currently can't support rowmarks in this case, because
|
||||||
|
* the associated junk CTIDs might have different resnos in
|
||||||
|
* different subplans.
|
||||||
|
*/
|
||||||
|
if (estate->es_rowMarks)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
|
||||||
|
errmsg("SELECT FOR UPDATE/SHARE is not supported within a query with multiple result relations")));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -771,6 +781,15 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|||||||
{
|
{
|
||||||
/* For SELECT, want to return the cleaned tuple type */
|
/* For SELECT, want to return the cleaned tuple type */
|
||||||
tupType = j->jf_cleanTupType;
|
tupType = j->jf_cleanTupType;
|
||||||
|
}
|
||||||
|
else if (operation == CMD_UPDATE || operation == CMD_DELETE)
|
||||||
|
{
|
||||||
|
/* For UPDATE/DELETE, find the ctid junk attr now */
|
||||||
|
j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
|
||||||
|
if (!AttributeNumberIsValid(j->jf_junkAttNo))
|
||||||
|
elog(ERROR, "could not find junk ctid column");
|
||||||
|
}
|
||||||
|
|
||||||
/* For SELECT FOR UPDATE/SHARE, find the ctid attrs now */
|
/* For SELECT FOR UPDATE/SHARE, find the ctid attrs now */
|
||||||
foreach(l, estate->es_rowMarks)
|
foreach(l, estate->es_rowMarks)
|
||||||
{
|
{
|
||||||
@ -784,17 +803,13 @@ InitPlan(QueryDesc *queryDesc, int eflags)
|
|||||||
resname);
|
resname);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (operation == CMD_UPDATE || operation == CMD_DELETE)
|
|
||||||
{
|
|
||||||
/* For UPDATE/DELETE, find the ctid junk attr now */
|
|
||||||
j->jf_junkAttNo = ExecFindJunkAttribute(j, "ctid");
|
|
||||||
if (!AttributeNumberIsValid(j->jf_junkAttNo))
|
|
||||||
elog(ERROR, "could not find junk ctid column");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
estate->es_junkFilter = NULL;
|
estate->es_junkFilter = NULL;
|
||||||
|
if (estate->es_rowMarks)
|
||||||
|
elog(ERROR, "SELECT FOR UPDATE/SHARE, but no junk columns");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -1240,40 +1255,21 @@ lnext: ;
|
|||||||
slot = planSlot;
|
slot = planSlot;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* if we have a junk filter, then project a new tuple with the junk
|
* If we have a junk filter, then project a new tuple with the junk
|
||||||
* removed.
|
* removed.
|
||||||
*
|
*
|
||||||
* Store this new "clean" tuple in the junkfilter's resultSlot.
|
* Store this new "clean" tuple in the junkfilter's resultSlot.
|
||||||
* (Formerly, we stored it back over the "dirty" tuple, which is WRONG
|
* (Formerly, we stored it back over the "dirty" tuple, which is WRONG
|
||||||
* because that tuple slot has the wrong descriptor.)
|
* because that tuple slot has the wrong descriptor.)
|
||||||
*
|
*
|
||||||
* Also, extract all the junk information we need.
|
* But first, extract all the junk information we need.
|
||||||
*/
|
*/
|
||||||
if ((junkfilter = estate->es_junkFilter) != NULL)
|
if ((junkfilter = estate->es_junkFilter) != NULL)
|
||||||
{
|
{
|
||||||
Datum datum;
|
|
||||||
bool isNull;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* extract the 'ctid' junk attribute.
|
|
||||||
*/
|
|
||||||
if (operation == CMD_UPDATE || operation == CMD_DELETE)
|
|
||||||
{
|
|
||||||
datum = ExecGetJunkAttribute(slot, junkfilter->jf_junkAttNo,
|
|
||||||
&isNull);
|
|
||||||
/* shouldn't ever get a null result... */
|
|
||||||
if (isNull)
|
|
||||||
elog(ERROR, "ctid is NULL");
|
|
||||||
|
|
||||||
tupleid = (ItemPointer) DatumGetPointer(datum);
|
|
||||||
tuple_ctid = *tupleid; /* make sure we don't free the ctid!! */
|
|
||||||
tupleid = &tuple_ctid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Process any FOR UPDATE or FOR SHARE locking requested.
|
* Process any FOR UPDATE or FOR SHARE locking requested.
|
||||||
*/
|
*/
|
||||||
else if (estate->es_rowMarks != NIL)
|
if (estate->es_rowMarks != NIL)
|
||||||
{
|
{
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
@ -1281,6 +1277,8 @@ lnext: ;
|
|||||||
foreach(l, estate->es_rowMarks)
|
foreach(l, estate->es_rowMarks)
|
||||||
{
|
{
|
||||||
ExecRowMark *erm = lfirst(l);
|
ExecRowMark *erm = lfirst(l);
|
||||||
|
Datum datum;
|
||||||
|
bool isNull;
|
||||||
HeapTupleData tuple;
|
HeapTupleData tuple;
|
||||||
Buffer buffer;
|
Buffer buffer;
|
||||||
ItemPointerData update_ctid;
|
ItemPointerData update_ctid;
|
||||||
@ -1352,6 +1350,25 @@ lnext: ;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extract the 'ctid' junk attribute.
|
||||||
|
*/
|
||||||
|
if (operation == CMD_UPDATE || operation == CMD_DELETE)
|
||||||
|
{
|
||||||
|
Datum datum;
|
||||||
|
bool isNull;
|
||||||
|
|
||||||
|
datum = ExecGetJunkAttribute(slot, junkfilter->jf_junkAttNo,
|
||||||
|
&isNull);
|
||||||
|
/* shouldn't ever get a null result... */
|
||||||
|
if (isNull)
|
||||||
|
elog(ERROR, "ctid is NULL");
|
||||||
|
|
||||||
|
tupleid = (ItemPointer) DatumGetPointer(datum);
|
||||||
|
tuple_ctid = *tupleid; /* make sure we don't free the ctid!! */
|
||||||
|
tupleid = &tuple_ctid;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create a new "clean" tuple with all junk attributes removed. We
|
* Create a new "clean" tuple with all junk attributes removed. We
|
||||||
* don't need to do this for DELETE, however (there will in fact
|
* don't need to do this for DELETE, however (there will in fact
|
||||||
|
Loading…
Reference in New Issue
Block a user