Skip site navigation (1) Skip section navigation (2)

Peripheral Links

Header And Logo

PostgreSQL
| The world's most advanced open source database.

Site Navigation

Search for
  Advanced Search

pl/pgsql: END verbosity [patch]



Hello

this patch allows optional using label with END and END LOOP. Ending label 
has only informational value, but can enhance readability large block and 
enhance likeness with Oracle.

<<main>>LOOP
 ...
 ...
END LOOP<<main>>;

Regards
Pavel Stehule
diff -c -r --new-file pgsql/doc/src/sgml/plpgsql.sgml pgsql.01/doc/src/sgml/plpgsql.sgml
*** pgsql/doc/src/sgml/plpgsql.sgml	2005-06-24 13:10:33.000000000 +0200
--- pgsql.01/doc/src/sgml/plpgsql.sgml	2005-06-25 15:29:27.000000000 +0200
***************
*** 456,462 ****
      <replaceable>declarations</replaceable> </optional>
  BEGIN
      <replaceable>statements</replaceable>
! END;
  </synopsis>
      </para>
  
--- 456,462 ----
      <replaceable>declarations</replaceable> </optional>
  BEGIN
      <replaceable>statements</replaceable>
! END <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>;
  </synopsis>
      </para>
  
***************
*** 1792,1798 ****
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
  
       <para>
--- 1792,1798 ----
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  LOOP
      <replaceable>statements</replaceable>
! END LOOP <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>;
  </synopsis>
  
       <para>
***************
*** 1923,1929 ****
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  WHILE <replaceable>expression</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
  
         <para>
--- 1923,1929 ----
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  WHILE <replaceable>expression</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>;
  </synopsis>
  
         <para>
***************
*** 2000,2006 ****
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  FOR <replaceable>record_or_row</replaceable> IN <replaceable>query</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
       The record or row variable is successively assigned each row
       resulting from the <replaceable>query</replaceable> (which must be a
--- 2000,2006 ----
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  FOR <replaceable>record_or_row</replaceable> IN <replaceable>query</replaceable> LOOP
      <replaceable>statements</replaceable>
! END LOOP <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>;
  </synopsis>
       The record or row variable is successively assigned each row
       resulting from the <replaceable>query</replaceable> (which must be a
***************
*** 2039,2045 ****
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  FOR <replaceable>record_or_row</replaceable> IN EXECUTE <replaceable>text_expression</replaceable> LOOP 
      <replaceable>statements</replaceable>
! END LOOP;
  </synopsis>
       This is like the previous form, except that the source
       <command>SELECT</command> statement is specified as a string
--- 2039,2045 ----
  <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>
  FOR <replaceable>record_or_row</replaceable> IN EXECUTE <replaceable>text_expression</replaceable> LOOP 
      <replaceable>statements</replaceable>
! END LOOP <optional>&lt;&lt;<replaceable>label</replaceable>&gt;&gt;</optional>;
  </synopsis>
       This is like the previous form, except that the source
       <command>SELECT</command> statement is specified as a string
diff -c -r --new-file pgsql/src/pl/plpgsql/src/gram.y pgsql.01/src/pl/plpgsql/src/gram.y
*** pgsql/src/pl/plpgsql/src/gram.y	2005-06-24 13:11:25.000000000 +0200
--- pgsql.01/src/pl/plpgsql/src/gram.y	2005-06-25 15:21:22.000000000 +0200
***************
*** 56,61 ****
--- 56,62 ----
  											   PLpgSQL_datum *initial_datum);
  static	void			 check_sql_expr(const char *stmt);
  static	void			 plpgsql_sql_error_callback(void *arg);
+ static void 		check_labels(char *lbl, char *elbl, int lno);
  
  %}
  
***************
*** 81,86 ****
--- 82,93 ----
  			int  n_initvars;
  			int  *initvarnos;
  		}						declhdr;
+ 		struct 
+ 		{
+ 			char *label;
+ 			int lineno;
+ 			List *list;
+ 		}						loop_body;
  		List					*list;
  		PLpgSQL_type			*dtype;
  		PLpgSQL_datum			*scalar;	/* a VAR, RECFIELD, or TRIGARG */
***************
*** 122,129 ****
  %type <str>		opt_lblname opt_label
  %type <str>		opt_exitlabel
  %type <str>		execsql_start
  
! %type <list>	proc_sect proc_stmts stmt_else loop_body
  %type <stmt>	proc_stmt pl_block
  %type <stmt>	stmt_assign stmt_if stmt_loop stmt_while stmt_exit
  %type <stmt>	stmt_return stmt_return_next stmt_raise stmt_execsql
--- 129,138 ----
  %type <str>		opt_lblname opt_label
  %type <str>		opt_exitlabel
  %type <str>		execsql_start
+ %type <str>		opt_lbltext opt_endlabel
  
! %type <list>	proc_sect proc_stmts stmt_else
! %type <loop_body> loop_body
  %type <stmt>	proc_stmt pl_block
  %type <stmt>	stmt_assign stmt_if stmt_loop stmt_while stmt_exit
  %type <stmt>	stmt_return stmt_return_next stmt_raise stmt_execsql
***************
*** 248,257 ****
  				| ';'
  				;
  
! pl_block		: decl_sect K_BEGIN lno proc_sect exception_sect K_END
  					{
  						PLpgSQL_stmt_block *new;
  
  						new = palloc0(sizeof(PLpgSQL_stmt_block));
  
  						new->cmd_type	= PLPGSQL_STMT_BLOCK;
--- 257,268 ----
  				| ';'
  				;
  
! pl_block		: decl_sect K_BEGIN lno proc_sect exception_sect K_END opt_endlabel
  					{
  						PLpgSQL_stmt_block *new;
  
+ 						check_labels($1.label, $7, $3);
+ 						
  						new = palloc0(sizeof(PLpgSQL_stmt_block));
  
  						new->cmd_type	= PLPGSQL_STMT_BLOCK;
***************
*** 788,802 ****
  						new->cmd_type = PLPGSQL_STMT_LOOP;
  						new->lineno   = $3;
  						new->label	  = $1;
! 						new->body	  = $4;
! 
  						plpgsql_ns_pop();
  
  						$$ = (PLpgSQL_stmt *)new;
  					}
  				;
  
! stmt_while		: opt_label K_WHILE lno expr_until_loop loop_body
  					{
  						PLpgSQL_stmt_while *new;
  
--- 799,814 ----
  						new->cmd_type = PLPGSQL_STMT_LOOP;
  						new->lineno   = $3;
  						new->label	  = $1;
! 						new->body	  = $4.list;
! 						
! 						check_labels($1, $4.label, $4.lineno);
  						plpgsql_ns_pop();
  
  						$$ = (PLpgSQL_stmt *)new;
  					}
  				;
  
! stmt_while		: opt_label K_WHILE lno expr_until_loop loop_body 
  					{
  						PLpgSQL_stmt_while *new;
  
***************
*** 805,812 ****
  						new->lineno   = $3;
  						new->label	  = $1;
  						new->cond	  = $4;
! 						new->body	  = $5;
  
  						plpgsql_ns_pop();
  
  						$$ = (PLpgSQL_stmt *)new;
--- 817,826 ----
  						new->lineno   = $3;
  						new->label	  = $1;
  						new->cond	  = $4;
! 						new->body	  = $5.list;
  
+ 						check_labels($1, $5.label, $5.lineno);
+ 							
  						plpgsql_ns_pop();
  
  						$$ = (PLpgSQL_stmt *)new;
***************
*** 822,828 ****
  
  							new = (PLpgSQL_stmt_fori *) $3;
  							new->label	  = $1;
! 							new->body	  = $4;
  							$$ = (PLpgSQL_stmt *) new;
  						}
  						else if ($3->cmd_type == PLPGSQL_STMT_FORS)
--- 836,842 ----
  
  							new = (PLpgSQL_stmt_fori *) $3;
  							new->label	  = $1;
! 							new->body	  = $4.list;
  							$$ = (PLpgSQL_stmt *) new;
  						}
  						else if ($3->cmd_type == PLPGSQL_STMT_FORS)
***************
*** 831,837 ****
  
  							new = (PLpgSQL_stmt_fors *) $3;
  							new->label	  = $1;
! 							new->body	  = $4;
  							$$ = (PLpgSQL_stmt *) new;
  						}
  						else
--- 845,851 ----
  
  							new = (PLpgSQL_stmt_fors *) $3;
  							new->label	  = $1;
! 							new->body	  = $4.list;
  							$$ = (PLpgSQL_stmt *) new;
  						}
  						else
***************
*** 841,851 ****
  							Assert($3->cmd_type == PLPGSQL_STMT_DYNFORS);
  							new = (PLpgSQL_stmt_dynfors *) $3;
  							new->label	  = $1;
! 							new->body	  = $4;
  							$$ = (PLpgSQL_stmt *) new;
  						}
  
  						/* close namespace started in opt_label */
  						plpgsql_ns_pop();
  					}
  				;
--- 855,866 ----
  							Assert($3->cmd_type == PLPGSQL_STMT_DYNFORS);
  							new = (PLpgSQL_stmt_dynfors *) $3;
  							new->label	  = $1;
! 							new->body	  = $4.list;
  							$$ = (PLpgSQL_stmt *) new;
  						}
  
  						/* close namespace started in opt_label */
+ 						check_labels($1, $4.label, $4.lineno);
  						plpgsql_ns_pop();
  					}
  				;
***************
*** 1245,1252 ****
  					}
  				;
  
! loop_body		: proc_sect K_END K_LOOP ';'
! 					{ $$ = $1; }
  				;
  
  stmt_execsql	: execsql_start lno
--- 1260,1271 ----
  					}
  				;
  
! loop_body		: proc_sect lno K_END K_LOOP opt_endlabel ';'
! 					{ 
! 						$$.list = $1;
! 						$$.lineno = $2; 
! 						$$.label = $5;	
! 					}
  				;
  
  stmt_execsql	: execsql_start lno
***************
*** 1608,1621 ****
  					}
  				;
  
  opt_exitlabel	:
  					{ $$ = NULL; }
  				| T_LABEL
  					{
- 						char	*name;
- 
- 						plpgsql_convert_ident(yytext, &name, 1);
- 						$$ = name;
  					}
  				| T_WORD
  					{
--- 1627,1645 ----
  					}
  				;
  
+ opt_endlabel :				
+ 					{
+ 						$$ = NULL;
+ 					}
+ 				|  '<' '<' opt_lbltext '>' '>'
+ 					{
+ 						$$ = $3;
+ 					}
+ 				;
  opt_exitlabel	:
  					{ $$ = NULL; }
  				| T_LABEL
  					{
  					}
  				| T_WORD
  					{
***************
*** 1623,1628 ****
--- 1647,1662 ----
  						yyerror("no such label");
  					}
  				;
+ opt_lbltext :			T_LABEL
+ 					{
+ 						char * name;
+ 						plpgsql_convert_ident(yytext, &name, 1);
+ 						$$ = name;
+ 					}
+ 				| T_WORD
+ 					{
+ 						yyerror("no such label");
+ 					}
  
  opt_exitcond	: ';'
  					{ $$ = NULL; }
***************
*** 1630,1635 ****
--- 1664,1671 ----
  					{ $$ = $2; }
  				;
  
+ 
+ 
  opt_lblname		: T_WORD
  					{
  						char	*name;
***************
*** 2210,2213 ****
--- 2246,2267 ----
  	errposition(0);
  }
  
+ static void 
+ check_labels(char *lbl, char *elbl, int lno)
+ {
+ 	if (elbl)
+ 	{
+ 		if (lbl == NULL)
+ 		{
+ 			plpgsql_error_lineno = lno;
+ 			yyerror("Can't to specify end label without begin label.");
+ 		}
+ 		if (strcmp(lbl, elbl) != 0)
+ 		{
+ 			plpgsql_error_lineno = lno;
+ 			yyerror("End label is defferent block/loop label");
+ 		}
+ 	}
+ }
+ 
  #include "pl_scan.c"
diff -c -r --new-file pgsql/src/test/regress/expected/plpgsql.out pgsql.01/src/test/regress/expected/plpgsql.out
*** pgsql/src/test/regress/expected/plpgsql.out	2005-06-24 13:11:38.000000000 +0200
--- pgsql.01/src/test/regress/expected/plpgsql.out	2005-06-25 15:23:17.000000000 +0200
***************
*** 2666,2668 ****
--- 2666,2711 ----
  drop function continue_test2();
  drop function continue_test3();
  drop table conttesttbl;
+ -- verbose end block and end loop
+ create function vfoo() returns void as $$
+ <<blbl>>
+ begin
+   <<flbl1>>
+   for _i in 1 .. 10 loop
+     exit flbl1;
+   end loop <<flbl1>>;
+   <<flbl2>>
+   for _i in 1 .. 10 loop
+     exit flbl2;
+   end loop;
+ end <<blbl>>;
+ $$ language plpgsql;  
+ CREATE FUNCTION
+ create function vfoo2() returns void as $$
+ <<blbl>>
+ begin
+   for _i in 1 .. 10 loop
+     exit;
+   end loop <<flbl1>>;
+   <<flbl2>>
+   for _i in 1 .. 10 loop
+     exit flbl2;
+   end loop <<flbl3>>;
+ end <<blbl>>;
+ $$ language plpgsql;  
+ ERROR:  no such label at or near "flbl1" at character 107
+ LINE 6:   end loop <<flbl1>>;
+                      ^
+ select vfoo();
+  vfoo 
+ ------
+  
+ (1 row)
+ 
+ select fvoo2();
+ ERROR:  function fvoo2() does not exist
+ HINT:  No function matches the given name and argument types. You may need to add explicit type casts.
+ drop function vfoo();
+ DROP FUNCTION
+ drop function vfoo2();
+ ERROR:  function vfoo2() does not exist
diff -c -r --new-file pgsql/src/test/regress/sql/plpgsql.sql pgsql.01/src/test/regress/sql/plpgsql.sql
*** pgsql/src/test/regress/sql/plpgsql.sql	2005-06-24 13:11:35.000000000 +0200
--- pgsql.01/src/test/regress/sql/plpgsql.sql	2005-06-25 14:10:30.000000000 +0200
***************
*** 2232,2234 ****
--- 2232,2268 ----
  drop function continue_test2();
  drop function continue_test3();
  drop table conttesttbl;
+ 
+ -- verbose end block and end loop
+ create function vfoo() returns void as $$
+ <<blbl>>
+ begin
+   <<flbl1>>
+   for _i in 1 .. 10 loop
+     exit flbl1;
+   end loop <<flbl1>>;
+   <<flbl2>>
+   for _i in 1 .. 10 loop
+     exit flbl2;
+   end loop;
+ end <<blbl>>;
+ $$ language plpgsql;  
+ 
+ create function vfoo2() returns void as $$
+ <<blbl>>
+ begin
+   for _i in 1 .. 10 loop
+     exit;
+   end loop <<flbl1>>;
+   <<flbl2>>
+   for _i in 1 .. 10 loop
+     exit flbl2;
+   end loop <<flbl3>>;
+ end <<blbl>>;
+ $$ language plpgsql;  
+ 
+ select vfoo();
+ select fvoo2();
+ 
+ drop function vfoo();
+ drop function vfoo2();


Home | Main Index | Thread Index

Privacy Policy | PostgreSQL Archives hosted by Command Prompt, Inc. | Designed by tinysofa
Copyright © 1996 – 2008 PostgreSQL Global Development Group