mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-30 00:04:49 -04:00 
			
		
		
		
	Fix bug in CONTINUE statement for PL/pgSQL: when we continue a loop,
we need to be careful to reset rc to PLPGSQL_RC_OK, depending on how the loop's logic is structured. If we continue a loop but it then exits without executing the loop's body again, we want to return PLPGSQL_RC_OK to our caller. Enhance the regression tests to catch this problem. Per report from Michael Fuhr.
This commit is contained in:
		
							parent
							
								
									05db8b501b
								
							
						
					
					
						commit
						738df437b2
					
				| @ -3,7 +3,7 @@ | ||||
|  *			  procedural language | ||||
|  * | ||||
|  * IDENTIFICATION | ||||
|  *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.147 2005/06/22 01:35:02 neilc Exp $ | ||||
|  *	  $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.148 2005/06/22 07:28:47 neilc Exp $ | ||||
|  * | ||||
|  *	  This software is copyrighted by Jan Wieck - Hamburg. | ||||
|  * | ||||
| @ -1216,11 +1216,9 @@ exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt) | ||||
| static int | ||||
| exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt) | ||||
| { | ||||
| 	int			rc; | ||||
| 
 | ||||
| 	for (;;) | ||||
| 	{ | ||||
| 		rc = exec_stmts(estate, stmt->body); | ||||
| 		int rc = exec_stmts(estate, stmt->body); | ||||
| 
 | ||||
| 		switch (rc) | ||||
| 		{ | ||||
| @ -1271,12 +1269,12 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt) | ||||
| static int | ||||
| exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt) | ||||
| { | ||||
| 	bool		value; | ||||
| 	bool		isnull; | ||||
| 	int			rc; | ||||
| 
 | ||||
| 	for (;;) | ||||
| 	{ | ||||
| 		int			rc; | ||||
| 		bool		value; | ||||
| 		bool		isnull; | ||||
| 
 | ||||
| 		value = exec_eval_boolean(estate, stmt->cond, &isnull); | ||||
| 		exec_eval_cleanup(estate); | ||||
| 
 | ||||
| @ -1425,21 +1423,22 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt) | ||||
| 		else if (rc == PLPGSQL_RC_CONTINUE) | ||||
| 		{ | ||||
| 			if (estate->exitlabel == NULL) | ||||
| 				/* anonymous continue, so continue the current loop */ | ||||
| 				; | ||||
| 				/* anonymous continue, so re-run the current loop */ | ||||
| 				rc = PLPGSQL_RC_OK; | ||||
| 			else if (stmt->label != NULL && | ||||
| 					 strcmp(stmt->label, estate->exitlabel) == 0) | ||||
| 			{ | ||||
| 				/* labelled continue, matches the current stmt's label */ | ||||
| 				/* label matches named continue, so re-run loop */ | ||||
| 				estate->exitlabel = NULL; | ||||
| 				rc = PLPGSQL_RC_OK; | ||||
| 			} | ||||
| 			else | ||||
| 			{ | ||||
| 			    /*
 | ||||
| 				 * otherwise, this is a labelled continue that does | ||||
| 				 * not match the current statement's label, if any: | ||||
| 				 * return RC_CONTINUE so that the CONTINUE will | ||||
| 				 * propagate up the stack. | ||||
| 				 * otherwise, this is a named continue that does not | ||||
| 				 * match the current statement's label, if any: return | ||||
| 				 * RC_CONTINUE so that the CONTINUE will propagate up | ||||
| 				 * the stack. | ||||
| 				 */ | ||||
| 			    break; | ||||
| 			} | ||||
| @ -1555,18 +1554,22 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt) | ||||
| 				else if (rc == PLPGSQL_RC_CONTINUE) | ||||
| 				{ | ||||
| 					if (estate->exitlabel == NULL) | ||||
| 						/* unlabelled continue, continue the current loop */ | ||||
| 					{ | ||||
| 						/* anonymous continue, so re-run the current loop */ | ||||
| 						rc = PLPGSQL_RC_OK; | ||||
| 						continue; | ||||
| 					} | ||||
| 					else if (stmt->label != NULL && | ||||
| 							 strcmp(stmt->label, estate->exitlabel) == 0) | ||||
| 					{ | ||||
| 						/* labelled continue, matches the current stmt's label */ | ||||
| 						/* label matches named continue, so re-run loop */ | ||||
| 						rc = PLPGSQL_RC_OK; | ||||
| 						estate->exitlabel = NULL; | ||||
| 						continue; | ||||
| 					} | ||||
| 
 | ||||
| 					/*
 | ||||
| 					 * otherwise, we processed a labelled continue | ||||
| 					 * otherwise, we processed a named continue | ||||
| 					 * that does not match the current statement's | ||||
| 					 * label, if any: return RC_CONTINUE so that the | ||||
| 					 * CONTINUE will propagate up the stack. | ||||
| @ -2462,14 +2465,12 @@ static int | ||||
| exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt) | ||||
| { | ||||
| 	Datum		query; | ||||
| 	bool		isnull = false; | ||||
| 	bool		isnull; | ||||
| 	Oid			restype; | ||||
| 	char	   *querystr; | ||||
| 	PLpgSQL_rec *rec = NULL; | ||||
| 	PLpgSQL_row *row = NULL; | ||||
| 	SPITupleTable *tuptab; | ||||
| 	int			rc = PLPGSQL_RC_OK; | ||||
| 	int			i; | ||||
| 	int			n; | ||||
| 	void	   *plan; | ||||
| 	Portal		portal; | ||||
| @ -2536,8 +2537,12 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt) | ||||
| 	 */ | ||||
| 	while (n > 0) | ||||
| 	{ | ||||
| 		int			i; | ||||
| 
 | ||||
| 		for (i = 0; i < n; i++) | ||||
| 		{ | ||||
| 			int		rc; | ||||
| 
 | ||||
| 			/*
 | ||||
| 			 * Assign the tuple to the target | ||||
| 			 */ | ||||
|  | ||||
| @ -2547,7 +2547,33 @@ begin | ||||
|   for _r in execute 'select * from conttesttbl' loop | ||||
|     continue when _r.v <= 20; | ||||
|     raise notice '%', _r.v; | ||||
|   end loop;   | ||||
|   end loop; | ||||
| 
 | ||||
|   raise notice '---7---'; | ||||
|   for _i in 1..3 loop | ||||
|     raise notice '%', _i; | ||||
|     continue when _i = 3; | ||||
|   end loop; | ||||
| 
 | ||||
|   raise notice '---8---'; | ||||
|   _i := 1; | ||||
|   while _i <= 3 loop | ||||
|     raise notice '%', _i; | ||||
|     _i := _i + 1; | ||||
|     continue when _i = 3; | ||||
|   end loop; | ||||
| 
 | ||||
|   raise notice '---9---'; | ||||
|   for _r in select * from conttesttbl order by v limit 1 loop | ||||
|     raise notice '%', _r.v; | ||||
|     continue; | ||||
|   end loop; | ||||
| 
 | ||||
|   raise notice '---10---'; | ||||
|   for _r in execute 'select * from conttesttbl order by v limit 1' loop | ||||
|     raise notice '%', _r.v; | ||||
|     continue; | ||||
|   end loop; | ||||
| end; $$ language plpgsql; | ||||
| select continue_test1(); | ||||
| NOTICE:  ---1--- | ||||
| @ -2591,6 +2617,18 @@ NOTICE:  40 | ||||
| NOTICE:  ---6--- | ||||
| NOTICE:  30 | ||||
| NOTICE:  40 | ||||
| NOTICE:  ---7--- | ||||
| NOTICE:  1 | ||||
| NOTICE:  2 | ||||
| NOTICE:  3 | ||||
| NOTICE:  ---8--- | ||||
| NOTICE:  1 | ||||
| NOTICE:  2 | ||||
| NOTICE:  3 | ||||
| NOTICE:  ---9--- | ||||
| NOTICE:  10 | ||||
| NOTICE:  ---10--- | ||||
| NOTICE:  10 | ||||
|  continue_test1  | ||||
| ---------------- | ||||
|   | ||||
|  | ||||
| @ -2169,7 +2169,33 @@ begin | ||||
|   for _r in execute 'select * from conttesttbl' loop | ||||
|     continue when _r.v <= 20; | ||||
|     raise notice '%', _r.v; | ||||
|   end loop;   | ||||
|   end loop; | ||||
| 
 | ||||
|   raise notice '---7---'; | ||||
|   for _i in 1..3 loop | ||||
|     raise notice '%', _i; | ||||
|     continue when _i = 3; | ||||
|   end loop; | ||||
| 
 | ||||
|   raise notice '---8---'; | ||||
|   _i := 1; | ||||
|   while _i <= 3 loop | ||||
|     raise notice '%', _i; | ||||
|     _i := _i + 1; | ||||
|     continue when _i = 3; | ||||
|   end loop; | ||||
| 
 | ||||
|   raise notice '---9---'; | ||||
|   for _r in select * from conttesttbl order by v limit 1 loop | ||||
|     raise notice '%', _r.v; | ||||
|     continue; | ||||
|   end loop; | ||||
| 
 | ||||
|   raise notice '---10---'; | ||||
|   for _r in execute 'select * from conttesttbl order by v limit 1' loop | ||||
|     raise notice '%', _r.v; | ||||
|     continue; | ||||
|   end loop; | ||||
| end; $$ language plpgsql; | ||||
| 
 | ||||
| select continue_test1(); | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user