Hello
I cut controvers support for assign stmt. This patch is only
enhancing fore and fors stmts.

Regards
Pavel Stehule

_________________________________________________________________
Citite se osamele? Poznejte nekoho vyjmecneho diky Match.com. http://www.msn.cz/
diff -c -r pgsql/doc/src/sgml/plpgsql.sgml pgsql.new/doc/src/sgml/plpgsql.sgml
*** pgsql/doc/src/sgml/plpgsql.sgml	2005-12-08 19:02:04.000000000 +0100
--- pgsql.new/doc/src/sgml/plpgsql.sgml	2005-12-26 08:41:20.000000000 +0100
***************
*** 2008,2018 ****
       accordingly. The syntax is:
  <synopsis>
  <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> <replaceable>label</replaceable> </optional>;
  </synopsis>
!      The record or row variable is successively assigned each row
       resulting from the <replaceable>query</replaceable> (which must be a
       <command>SELECT</command> command) and the loop body is executed for each
       row. Here is an example:
--- 2008,2020 ----
       accordingly. The syntax is:
  <synopsis>
  <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
! FOR <replaceable>target</replaceable> IN <replaceable>query</replaceable> LOOP
      <replaceable>statements</replaceable>
  END LOOP <optional> <replaceable>label</replaceable> </optional>;
  </synopsis>
!      <replaceable>Target</replaceable> is a record variable, row variable, 
!      or a comma-separated list of  simple variables and record/row fields
!      which is successively assigned each row
       resulting from the <replaceable>query</replaceable> (which must be a
       <command>SELECT</command> command) and the loop body is executed for each
       row. Here is an example:
***************
*** 2047,2053 ****
       rows:
  <synopsis>
  <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> <replaceable>label</replaceable> </optional>;
  </synopsis>
--- 2049,2055 ----
       rows:
  <synopsis>
  <optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
! FOR <replaceable>target</replaceable> IN EXECUTE <replaceable>text_expression</replaceable> LOOP 
      <replaceable>statements</replaceable>
  END LOOP <optional> <replaceable>label</replaceable> </optional>;
  </synopsis>
***************
*** 2067,2073 ****
       <literal>IN</> and <literal>LOOP</>.  If <literal>..</> is not seen then
       the loop is presumed to be a loop over rows.  Mistyping the <literal>..</>
       is thus likely to lead to a complaint along the lines of
!      <quote>loop variable of loop over rows must be a record or row variable</>,
       rather than the simple syntax error one might expect to get.
      </para>
      </note>
--- 2069,2075 ----
       <literal>IN</> and <literal>LOOP</>.  If <literal>..</> is not seen then
       the loop is presumed to be a loop over rows.  Mistyping the <literal>..</>
       is thus likely to lead to a complaint along the lines of
!      <quote>loop variable of loop over rows must be a record or row or scalar variable</>,
       rather than the simple syntax error one might expect to get.
      </para>
      </note>
diff -c -r pgsql/src/pl/plpgsql/src/gram.y pgsql.new/src/pl/plpgsql/src/gram.y
*** pgsql/src/pl/plpgsql/src/gram.y	2005-10-13 17:34:19.000000000 +0200
--- pgsql.new/src/pl/plpgsql/src/gram.y	2005-12-26 12:29:10.000000000 +0100
***************
*** 58,64 ****
  static	void			 plpgsql_sql_error_callback(void *arg);
  static	void			 check_labels(const char *start_label,
  									  const char *end_label);
! 
  %}
  
  %union {
--- 58,66 ----
  static	void			 plpgsql_sql_error_callback(void *arg);
  static	void			 check_labels(const char *start_label,
  									  const char *end_label);
! static PLpgSQL_row       *make_scalar_list1(const char *name,
! 					    PLpgSQL_datum *variable);
!  
  %}
  
  %union {
***************
*** 76,81 ****
--- 78,84 ----
  			int  lineno;
  			PLpgSQL_rec     *rec;
  			PLpgSQL_row     *row;
+ 		        PLpgSQL_datum   *scalar;
  		}						forvariable;
  		struct
  		{
***************
*** 884,893 ****
  								new->rec = $2.rec;
  							else if ($2.row)
  								new->row = $2.row;
  							else
  							{
  								plpgsql_error_lineno = $1;
! 								yyerror("loop variable of loop over rows must be a record or row variable");
  							}
  							new->query = expr;
  
--- 887,898 ----
  								new->rec = $2.rec;
  							else if ($2.row)
  								new->row = $2.row;
+ 							else if ($2.scalar)
+ 							        new->row = make_scalar_list1($2.name, $2.scalar);
  							else
  							{
  								plpgsql_error_lineno = $1;
! 								yyerror("loop variable of loop over rows must be a record or row or scalar variable");
  							}
  							new->query = expr;
  
***************
*** 942,947 ****
--- 947,961 ----
  
  								expr2 = plpgsql_read_expression(K_LOOP, "LOOP");
  
+ 								/* T_SCALAR identifier waits for converting */
+ 								if ($2.scalar)
+ 								{
+ 								    char *name;
+ 								    plpgsql_convert_ident($2.name, &name, 1);
+ 								    pfree($2.name);
+ 								    $2.name = name;
+ 								}
+ 
  								fvar = (PLpgSQL_var *)
  									plpgsql_build_variable($2.name,
  														   $2.lineno,
***************
*** 989,998 ****
  									new->rec = $2.rec;
  								else if ($2.row)
  									new->row = $2.row;
  								else
  								{
  									plpgsql_error_lineno = $1;
! 									yyerror("loop variable of loop over rows must be record or row variable");
  								}
  
  								new->query = expr1;
--- 1003,1014 ----
  									new->rec = $2.rec;
  								else if ($2.row)
  									new->row = $2.row;
+ 								else if ($2.scalar)
+ 								        new->row = make_scalar_list1($2.name, $2.scalar);
  								else
  								{
  									plpgsql_error_lineno = $1;
! 									yyerror("loop variable of loop over rows must be record or row or scalar variable");
  								}
  
  								new->query = expr1;
***************
*** 1004,1016 ****
  
  for_variable	: T_SCALAR
  					{
  						char		*name;
! 
! 						plpgsql_convert_ident(yytext, &name, 1);
! 						$$.name = name;
! 						$$.lineno  = plpgsql_scanner_lineno();
! 						$$.rec = NULL;
! 						$$.row = NULL;
  					}
  				| T_WORD
  					{
--- 1020,1049 ----
  
  for_variable	: T_SCALAR
  					{
+ 					        int tok;
  						char		*name;
! 						
! 						name = pstrdup(yytext);
! 						$$.scalar = yylval.scalar;
! 						$$.lineno = plpgsql_scanner_lineno();
! 
! 						if((tok = yylex()) == ',')
! 						{
! 						    plpgsql_push_back_token(tok);
! 						    $$.name = NULL;
! 						    $$.row = read_into_scalar_list(name, $$.scalar);
! 						    $$.rec = NULL;
! 						    $$.scalar = NULL;
! 						    
! 						    pfree(name);
! 						}
! 						else
! 						{
! 						    plpgsql_push_back_token(tok);
! 						    $$.name = name;
! 						    $$.row = NULL;
! 						    $$.rec = NULL;
! 						}
  					}
  				| T_WORD
  					{
***************
*** 1024,1043 ****
  					}
  				| T_RECORD
  					{
! 						char		*name;
! 
! 						plpgsql_convert_ident(yytext, &name, 1);
! 						$$.name = name;
  						$$.lineno  = plpgsql_scanner_lineno();
  						$$.rec = yylval.rec;
  						$$.row = NULL;
  					}
  				| T_ROW
  					{
! 						char		*name;
! 
! 						plpgsql_convert_ident(yytext, &name, 1);
! 						$$.name = name;
  						$$.lineno  = plpgsql_scanner_lineno();
  						$$.row = yylval.row;
  						$$.rec = NULL;
--- 1057,1070 ----
  					}
  				| T_RECORD
  					{
! 						$$.name = NULL;
  						$$.lineno  = plpgsql_scanner_lineno();
  						$$.rec = yylval.rec;
  						$$.row = NULL;
  					}
  				| T_ROW
  					{
! 					        $$.name = NULL;
  						$$.lineno  = plpgsql_scanner_lineno();
  						$$.row = yylval.row;
  						$$.rec = NULL;
***************
*** 2055,2060 ****
--- 2082,2111 ----
  }
  
  
+ static PLpgSQL_row *
+ make_scalar_list1(const char *name,
+  				  PLpgSQL_datum *variable)
+ {
+  	PLpgSQL_row		*row;
+  	check_assignable(variable);
+  	
+  	row = palloc(sizeof(PLpgSQL_row));
+  	row->dtype = PLPGSQL_DTYPE_ROW;
+  	row->refname = pstrdup("*internal*");
+  	row->lineno = plpgsql_scanner_lineno();
+  	row->rowtupdesc = NULL;
+  	row->nfields = 1;
+  	row->fieldnames = palloc(sizeof(char *) * 1);
+  	row->varnos = palloc(sizeof(int) * 1);
+  	row->fieldnames[0] = pstrdup(name);
+  	row->varnos[0] = variable->dno;
+  
+  	plpgsql_adddatum((PLpgSQL_datum *)row);
+  
+  	return row;
+ } 
+ 
+ 
  static void
  check_assignable(PLpgSQL_datum *datum)
  {
diff -c -r pgsql/src/test/regress/sql/plpgsql.sql pgsql.new/src/test/regress/sql/plpgsql.sql
*** pgsql/src/test/regress/sql/plpgsql.sql	2005-09-14 20:35:38.000000000 +0200
--- pgsql.new/src/test/regress/sql/plpgsql.sql	2005-12-26 08:37:02.000000000 +0100
***************
*** 2280,2282 ****
--- 2280,2304 ----
    end loop outer_label;
  end;
  $$ language plpgsql;
+ 
+ 
+ -- using list of scalars in fori and fore stmts
+ create function for_vect() returns void as $$
+ <<lbl>>declare a integer; b varchar; c varchar; r record;
+ begin
+   -- old fori
+   for i in 1 .. 10 loop
+     raise notice '%', i;
+   end loop;
+   for a in select 1 from generate_series(1,4) loop
+     raise notice '%', a;
+   end loop;
+   for a,b,c in select generate_series, 'BB','CC' from generate_series(1,4) loop
+     raise notice '% % %', a, b, c;
+   end loop;
+   -- using qualified names in fors, fore is enabled, disabled only for fori
+   for lbl.a, lbl.b, lbl.c in execute E'select generate_series, \'bb\',\'cc\' from generate_series(1,4)' loop
+     raise notice '% % %', a, b, c;
+   end loop;
+ end;
+ $$ language plpgsql;

---------------------------(end of broadcast)---------------------------
TIP 6: explain analyze is your friend

Reply via email to