Skip to content

Commit f593f62

Browse files
committed
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.
1 parent 819b49a commit f593f62

File tree

1 file changed

+52
-35
lines changed

1 file changed

+52
-35
lines changed

src/backend/executor/execMain.c

Lines changed: 52 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@
2626
*
2727
*
2828
* IDENTIFICATION
29-
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.305 2008/03/28 00:21:55 tgl Exp $
29+
* $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.306 2008/04/21 03:49:45 tgl Exp $
3030
*
3131
*-------------------------------------------------------------------------
3232
*/
@@ -754,6 +754,16 @@ InitPlan(QueryDesc *queryDesc, int eflags)
754754
*/
755755
estate->es_junkFilter =
756756
estate->es_result_relation_info->ri_junkFilter;
757+
758+
/*
759+
* We currently can't support rowmarks in this case, because
760+
* the associated junk CTIDs might have different resnos in
761+
* different subplans.
762+
*/
763+
if (estate->es_rowMarks)
764+
ereport(ERROR,
765+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
766+
errmsg("SELECT FOR UPDATE/SHARE is not supported within a query with multiple result relations")));
757767
}
758768
else
759769
{
@@ -771,18 +781,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
771781
{
772782
/* For SELECT, want to return the cleaned tuple type */
773783
tupType = j->jf_cleanTupType;
774-
/* For SELECT FOR UPDATE/SHARE, find the ctid attrs now */
775-
foreach(l, estate->es_rowMarks)
776-
{
777-
ExecRowMark *erm = (ExecRowMark *) lfirst(l);
778-
char resname[32];
779-
780-
snprintf(resname, sizeof(resname), "ctid%u", erm->rti);
781-
erm->ctidAttNo = ExecFindJunkAttribute(j, resname);
782-
if (!AttributeNumberIsValid(erm->ctidAttNo))
783-
elog(ERROR, "could not find junk \"%s\" column",
784-
resname);
785-
}
786784
}
787785
else if (operation == CMD_UPDATE || operation == CMD_DELETE)
788786
{
@@ -791,10 +789,27 @@ InitPlan(QueryDesc *queryDesc, int eflags)
791789
if (!AttributeNumberIsValid(j->jf_junkAttNo))
792790
elog(ERROR, "could not find junk ctid column");
793791
}
792+
793+
/* For SELECT FOR UPDATE/SHARE, find the ctid attrs now */
794+
foreach(l, estate->es_rowMarks)
795+
{
796+
ExecRowMark *erm = (ExecRowMark *) lfirst(l);
797+
char resname[32];
798+
799+
snprintf(resname, sizeof(resname), "ctid%u", erm->rti);
800+
erm->ctidAttNo = ExecFindJunkAttribute(j, resname);
801+
if (!AttributeNumberIsValid(erm->ctidAttNo))
802+
elog(ERROR, "could not find junk \"%s\" column",
803+
resname);
804+
}
794805
}
795806
}
796807
else
808+
{
797809
estate->es_junkFilter = NULL;
810+
if (estate->es_rowMarks)
811+
elog(ERROR, "SELECT FOR UPDATE/SHARE, but no junk columns");
812+
}
798813
}
799814

800815
/*
@@ -1240,47 +1255,30 @@ lnext: ;
12401255
slot = planSlot;
12411256

12421257
/*
1243-
* if we have a junk filter, then project a new tuple with the junk
1258+
* If we have a junk filter, then project a new tuple with the junk
12441259
* removed.
12451260
*
12461261
* Store this new "clean" tuple in the junkfilter's resultSlot.
12471262
* (Formerly, we stored it back over the "dirty" tuple, which is WRONG
12481263
* because that tuple slot has the wrong descriptor.)
12491264
*
1250-
* Also, extract all the junk information we need.
1265+
* But first, extract all the junk information we need.
12511266
*/
12521267
if ((junkfilter = estate->es_junkFilter) != NULL)
12531268
{
1254-
Datum datum;
1255-
bool isNull;
1256-
1257-
/*
1258-
* extract the 'ctid' junk attribute.
1259-
*/
1260-
if (operation == CMD_UPDATE || operation == CMD_DELETE)
1261-
{
1262-
datum = ExecGetJunkAttribute(slot, junkfilter->jf_junkAttNo,
1263-
&isNull);
1264-
/* shouldn't ever get a null result... */
1265-
if (isNull)
1266-
elog(ERROR, "ctid is NULL");
1267-
1268-
tupleid = (ItemPointer) DatumGetPointer(datum);
1269-
tuple_ctid = *tupleid; /* make sure we don't free the ctid!! */
1270-
tupleid = &tuple_ctid;
1271-
}
1272-
12731269
/*
12741270
* Process any FOR UPDATE or FOR SHARE locking requested.
12751271
*/
1276-
else if (estate->es_rowMarks != NIL)
1272+
if (estate->es_rowMarks != NIL)
12771273
{
12781274
ListCell *l;
12791275

12801276
lmark: ;
12811277
foreach(l, estate->es_rowMarks)
12821278
{
12831279
ExecRowMark *erm = lfirst(l);
1280+
Datum datum;
1281+
bool isNull;
12841282
HeapTupleData tuple;
12851283
Buffer buffer;
12861284
ItemPointerData update_ctid;
@@ -1352,6 +1350,25 @@ lnext: ;
13521350
}
13531351
}
13541352

1353+
/*
1354+
* extract the 'ctid' junk attribute.
1355+
*/
1356+
if (operation == CMD_UPDATE || operation == CMD_DELETE)
1357+
{
1358+
Datum datum;
1359+
bool isNull;
1360+
1361+
datum = ExecGetJunkAttribute(slot, junkfilter->jf_junkAttNo,
1362+
&isNull);
1363+
/* shouldn't ever get a null result... */
1364+
if (isNull)
1365+
elog(ERROR, "ctid is NULL");
1366+
1367+
tupleid = (ItemPointer) DatumGetPointer(datum);
1368+
tuple_ctid = *tupleid; /* make sure we don't free the ctid!! */
1369+
tupleid = &tuple_ctid;
1370+
}
1371+
13551372
/*
13561373
* Create a new "clean" tuple with all junk attributes removed. We
13571374
* don't need to do this for DELETE, however (there will in fact

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy