diff -c -r pgsql.old/doc/src/sgml/plpgsql.sgml pgsql2/doc/src/sgml/plpgsql.sgml
*** pgsql.old/doc/src/sgml/plpgsql.sgml 2005-12-08 19:02:04.000000000 +0100
--- pgsql2/doc/src/sgml/plpgsql.sgml 2005-12-19 20:49:08.000000000 +0100
***************
*** 1024,1037 ****
Assignment
! An assignment of a value to a variable or row/record field is
! written as:
! identifier := expression;
As explained above, the expression in such a statement is evaluated
by means of an SQL SELECT> command sent to the main
! database engine. The expression must yield a single value.
--- 1024,1040 ----
Assignment
! An assignment of a value to a variable or row/record of field or list of
! variables is written as:
! target := expression;
As explained above, the expression in such a statement is evaluated
by means of an SQL SELECT> command sent to the main
! database engine. The expression must yield a single scalar, row, or record
! value. Target is a
! record variable, row variable, or a comma-separated list of
! simple variables and record/row fields.
***************
*** 1050,1055 ****
--- 1053,1059 ----
user_id := 20;
tax := subtotal * 0.06;
+ x, y, z := ROW(10,20,30);
***************
*** 2008,2018 ****
accordingly. The syntax is:
<<label>>
! FOR record_or_row IN query LOOP
statements
END LOOP label ;
! The record or row variable is successively assigned each row
resulting from the query (which must be a
SELECT command) and the loop body is executed for each
row. Here is an example:
--- 2012,2024 ----
accordingly. The syntax is:
<<label>>
! FOR target IN query LOOP
statements
END LOOP label ;
! Target 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 query (which must be a
SELECT command) and the loop body is executed for each
row. Here is an example:
***************
*** 2047,2053 ****
rows:
<<label>>
! FOR record_or_row IN EXECUTE text_expression LOOP
statements
END LOOP label ;
--- 2053,2059 ----
rows:
<<label>>
! FOR target IN EXECUTE text_expression LOOP
statements
END LOOP label ;
***************
*** 2056,2062 ****
expression, which is evaluated and replanned on each entry to
the FOR> loop. This allows the programmer to choose the speed of
a preplanned query or the flexibility of a dynamic query, just
! as with a plain EXECUTE statement.
--- 2062,2070 ----
expression, which is evaluated and replanned on each entry to
the FOR> loop. This allows the programmer to choose the speed of
a preplanned query or the flexibility of a dynamic query, just
! as with a plain EXECUTE statement. Target is a
! record variable, row variable, or a comma-separated list of
! simple variables and record/row fields
diff -c -r pgsql.old/src/pl/plpgsql/src/gram.y pgsql2/src/pl/plpgsql/src/gram.y
*** pgsql.old/src/pl/plpgsql/src/gram.y 2005-10-13 17:34:19.000000000 +0200
--- pgsql2/src/pl/plpgsql/src/gram.y 2005-12-19 18:56:21.000000000 +0100
***************
*** 59,64 ****
--- 59,67 ----
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 ****
--- 79,85 ----
int lineno;
PLpgSQL_rec *rec;
PLpgSQL_row *row;
+ PLpgSQL_datum *scalar;
} forvariable;
struct
{
***************
*** 709,716 ****
assign_var : T_SCALAR
{
! check_assignable(yylval.scalar);
! $$ = yylval.scalar->dno;
}
| T_ROW
{
--- 713,736 ----
assign_var : T_SCALAR
{
! int tok;
! PLpgSQL_datum *var = yylval.scalar;
! char *name = pstrdup(yytext);
!
! if ((tok = yylex()) == ',')
! {
! PLpgSQL_row *row;
!
! plpgsql_push_back_token(tok);
! row = read_into_scalar_list(name, var);
! $$ = row->rowno;
! }
! else
! {
! plpgsql_push_back_token(tok);
! check_assignable(var);
! $$ = var->dno;
! }
}
| T_ROW
{
***************
*** 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;
--- 904,915 ----
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 ****
--- 964,978 ----
expr2 = plpgsql_read_expression(K_LOOP, "LOOP");
+ /* T_WORD identifier is converted */
+ 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;
--- 1020,1031 ----
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
{
--- 1037,1066 ----
for_variable : T_SCALAR
{
! char * name;
! int tok;
!
! 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,1046 ****
}
| 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;
}
;
--- 1074,1092 ----
}
| T_RECORD
{
! $$.name = NULL;
$$.lineno = plpgsql_scanner_lineno();
$$.rec = yylval.rec;
$$.row = NULL;
+ $$.scalar = NULL;
}
| T_ROW
{
! $$.name = NULL;
$$.lineno = plpgsql_scanner_lineno();
$$.row = yylval.row;
$$.rec = NULL;
+ $$.scalar = NULL;
}
;
***************
*** 2166,2171 ****
--- 2212,2241 ----
return row;
}
+ 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;
+ }
+
+
/*
* When the PL/PgSQL parser expects to see a SQL statement, it is very
* liberal in what it accepts; for example, we often assume an
diff -c -r pgsql.old/src/test/regress/sql/plpgsql.sql pgsql2/src/test/regress/sql/plpgsql.sql
*** pgsql.old/src/test/regress/sql/plpgsql.sql 2005-09-14 20:35:38.000000000 +0200
--- pgsql2/src/test/regress/sql/plpgsql.sql 2005-12-19 19:55:38.000000000 +0100
***************
*** 2280,2282 ****
--- 2280,2306 ----
end loop outer_label;
end;
$$ language plpgsql;
+
+ create function for_vect() returns void as $$
+ <>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;
+ for r in select generate_series+1, generate_series+2 from generate_series(1,4) loop
+ a, b := r;
+ raise notice '% %', a,b;
+ end loop;
+ end;
+ $$ language plpgsql;