This patch moves some code for preprocessing FOR UPDATE from grouping_planner() to preprocess_targetlist(), according to a comment in grouping_planner(). I think the refactoring makes sense, and moves some extraneous details out of grouping_planner().

Barring any objections, I'll apply this to HEAD tonight or tomorrow.

-Neil
Index: src/backend/optimizer/plan/planner.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/optimizer/plan/planner.c,v
retrieving revision 1.179
diff -c -r1.179 planner.c
*** src/backend/optimizer/plan/planner.c	10 Mar 2005 23:21:22 -0000	1.179
--- src/backend/optimizer/plan/planner.c	17 Mar 2005 06:33:03 -0000
***************
*** 36,42 ****
  #include "optimizer/subselect.h"
  #include "optimizer/tlist.h"
  #include "optimizer/var.h"
- #include "parser/analyze.h"
  #include "parser/parsetree.h"
  #include "parser/parse_expr.h"
  #include "parser/parse_oper.h"
--- 36,41 ----
***************
*** 698,762 ****
  
  		MemSet(&agg_counts, 0, sizeof(AggClauseCounts));
  
! 		/* Preprocess targetlist in case we are inside an INSERT/UPDATE. */
! 		tlist = preprocess_targetlist(tlist,
! 									  parse->commandType,
! 									  parse->resultRelation,
! 									  parse->rtable);
! 
! 		/*
! 		 * Add TID targets for rels selected FOR UPDATE (should this be
! 		 * done in preprocess_targetlist?).  The executor uses the TID to
! 		 * know which rows to lock, much as for UPDATE or DELETE.
! 		 */
! 		if (parse->rowMarks)
! 		{
! 			ListCell   *l;
! 
! 			/*
! 			 * We've got trouble if the FOR UPDATE appears inside
! 			 * grouping, since grouping renders a reference to individual
! 			 * tuple CTIDs invalid.  This is also checked at parse time,
! 			 * but that's insufficient because of rule substitution, query
! 			 * pullup, etc.
! 			 */
! 			CheckSelectForUpdate(parse);
! 
! 			/*
! 			 * Currently the executor only supports FOR UPDATE at top
! 			 * level
! 			 */
! 			if (PlannerQueryLevel > 1)
! 				ereport(ERROR,
! 						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
! 						 errmsg("SELECT FOR UPDATE is not allowed in subqueries")));
! 
! 			foreach(l, parse->rowMarks)
! 			{
! 				Index		rti = lfirst_int(l);
! 				char	   *resname;
! 				Resdom	   *resdom;
! 				Var		   *var;
! 				TargetEntry *ctid;
! 
! 				resname = (char *) palloc(32);
! 				snprintf(resname, 32, "ctid%u", rti);
! 				resdom = makeResdom(list_length(tlist) + 1,
! 									TIDOID,
! 									-1,
! 									resname,
! 									true);
! 
! 				var = makeVar(rti,
! 							  SelfItemPointerAttributeNumber,
! 							  TIDOID,
! 							  -1,
! 							  0);
! 
! 				ctid = makeTargetEntry(resdom, (Expr *) var);
! 				tlist = lappend(tlist, ctid);
! 			}
! 		}
  
  		/*
  		 * Generate appropriate target list for subplan; may be different
--- 697,704 ----
  
  		MemSet(&agg_counts, 0, sizeof(AggClauseCounts));
  
! 		/* Preprocess targetlist */
! 		tlist = preprocess_targetlist(parse, tlist);
  
  		/*
  		 * Generate appropriate target list for subplan; may be different
Index: src/backend/optimizer/prep/preptlist.c
===================================================================
RCS file: /var/lib/cvs/pgsql/src/backend/optimizer/prep/preptlist.c,v
retrieving revision 1.72
diff -c -r1.72 preptlist.c
*** src/backend/optimizer/prep/preptlist.c	31 Dec 2004 22:00:20 -0000	1.72
--- src/backend/optimizer/prep/preptlist.c	17 Mar 2005 06:34:37 -0000
***************
*** 26,31 ****
--- 26,33 ----
  #include "catalog/pg_type.h"
  #include "nodes/makefuncs.h"
  #include "optimizer/prep.h"
+ #include "optimizer/subselect.h"
+ #include "parser/analyze.h"
  #include "parser/parsetree.h"
  #include "parser/parse_coerce.h"
  
***************
*** 41,51 ****
   *	  Returns the new targetlist.
   */
  List *
! preprocess_targetlist(List *tlist,
! 					  int command_type,
! 					  Index result_relation,
! 					  List *range_table)
  {
  	/*
  	 * Sanity check: if there is a result relation, it'd better be a real
  	 * relation not a subquery.  Else parser or rewriter messed up.
--- 43,54 ----
   *	  Returns the new targetlist.
   */
  List *
! preprocess_targetlist(Query *parse, List *tlist)
  {
+ 	int		result_relation = parse->resultRelation;
+ 	List   *range_table = parse->rtable;
+ 	CmdType	command_type = parse->commandType;
+ 
  	/*
  	 * Sanity check: if there is a result relation, it'd better be a real
  	 * relation not a subquery.  Else parser or rewriter messed up.
***************
*** 99,104 ****
--- 102,161 ----
  		tlist = lappend(tlist, makeTargetEntry(resdom, (Expr *) var));
  	}
  
+ 	/*
+ 	 * Add TID targets for rels selected FOR UPDATE.  The executor
+ 	 * uses the TID to know which rows to lock, much as for UPDATE or
+ 	 * DELETE.
+ 	 */
+ 	if (parse->rowMarks)
+ 	{
+ 		ListCell   *l;
+ 
+ 		/*
+ 		 * We've got trouble if the FOR UPDATE appears inside
+ 		 * grouping, since grouping renders a reference to individual
+ 		 * tuple CTIDs invalid.  This is also checked at parse time,
+ 		 * but that's insufficient because of rule substitution, query
+ 		 * pullup, etc.
+ 		 */
+ 		CheckSelectForUpdate(parse);
+ 
+ 		/*
+ 		 * Currently the executor only supports FOR UPDATE at top
+ 		 * level
+ 		 */
+ 		if (PlannerQueryLevel > 1)
+ 			ereport(ERROR,
+ 					(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ 					 errmsg("SELECT FOR UPDATE is not allowed in subqueries")));
+ 
+ 		foreach(l, parse->rowMarks)
+ 		{
+ 			Index		rti = lfirst_int(l);
+ 			char	   *resname;
+ 			Resdom	   *resdom;
+ 			Var		   *var;
+ 			TargetEntry *ctid;
+ 
+ 			resname = (char *) palloc(32);
+ 			snprintf(resname, 32, "ctid%u", rti);
+ 			resdom = makeResdom(list_length(tlist) + 1,
+ 								TIDOID,
+ 								-1,
+ 								resname,
+ 								true);
+ 
+ 			var = makeVar(rti,
+ 						  SelfItemPointerAttributeNumber,
+ 						  TIDOID,
+ 						  -1,
+ 						  0);
+ 
+ 			ctid = makeTargetEntry(resdom, (Expr *) var);
+ 			tlist = lappend(tlist, ctid);
+ 		}
+ 	}
+ 
  	return tlist;
  }
  
Index: src/include/optimizer/prep.h
===================================================================
RCS file: /var/lib/cvs/pgsql/src/include/optimizer/prep.h,v
retrieving revision 1.47
diff -c -r1.47 prep.h
*** src/include/optimizer/prep.h	31 Dec 2004 22:03:36 -0000	1.47
--- src/include/optimizer/prep.h	17 Mar 2005 06:22:32 -0000
***************
*** 42,49 ****
  /*
   * prototypes for preptlist.c
   */
! extern List *preprocess_targetlist(List *tlist, int command_type,
! 					  Index result_relation, List *range_table);
  
  /*
   * prototypes for prepunion.c
--- 42,48 ----
  /*
   * prototypes for preptlist.c
   */
! extern List *preprocess_targetlist(Query *parse, List *tlist);
  
  /*
   * prototypes for prepunion.c
---------------------------(end of broadcast)---------------------------
TIP 1: subscribe and unsubscribe commands go to [EMAIL PROTECTED]

Reply via email to