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 */
755755estate -> es_junkFilter =
756756estate -> 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}
758768else
759769{
@@ -771,18 +781,6 @@ InitPlan(QueryDesc *queryDesc, int eflags)
771781{
772782/* For SELECT, want to return the cleaned tuple type */
773783tupType = 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}
787785else if (operation == CMD_UPDATE || operation == CMD_DELETE )
788786{
@@ -791,10 +789,27 @@ InitPlan(QueryDesc *queryDesc, int eflags)
791789if (!AttributeNumberIsValid (j -> jf_junkAttNo ))
792790elog (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}
796807else
808+ {
797809estate -> 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:;
12401255slot = 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 */
12521267if ((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{
12781274ListCell * l ;
12791275
12801276lmark :;
12811277foreach (l ,estate -> es_rowMarks )
12821278{
12831279ExecRowMark * erm = lfirst (l );
1280+ Datum datum ;
1281+ bool isNull ;
12841282HeapTupleData tuple ;
12851283Buffer buffer ;
12861284ItemPointerData 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