Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
P
Postgres FD Implementation
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Abuhujair Javed
Postgres FD Implementation
Commits
025ffe58
Commit
025ffe58
authored
Feb 12, 2006
by
Bruce Momjian
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Allow PL/pgSQL FOR statement to return values to scalars as well as
records and row types. Pavel Stehule
parent
18cbc7ae
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
124 additions
and
23 deletions
+124
-23
doc/src/sgml/plpgsql.sgml
doc/src/sgml/plpgsql.sgml
+7
-5
src/pl/plpgsql/src/gram.y
src/pl/plpgsql/src/gram.y
+75
-18
src/test/regress/expected/plpgsql.out
src/test/regress/expected/plpgsql.out
+20
-0
src/test/regress/sql/plpgsql.sql
src/test/regress/sql/plpgsql.sql
+22
-0
No files found.
doc/src/sgml/plpgsql.sgml
View file @
025ffe58
<!--
<!--
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.8
4 2006/02/05 02:47:53
momjian Exp $
$PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.8
5 2006/02/12 06:03:38
momjian Exp $
-->
-->
<chapter id="plpgsql">
<chapter id="plpgsql">
...
@@ -2008,11 +2008,13 @@ END LOOP;
...
@@ -2008,11 +2008,13 @@ END LOOP;
accordingly. The syntax is:
accordingly. The syntax is:
<synopsis>
<synopsis>
<optional> <<<replaceable>label</replaceable>>> </optional>
<optional> <<<replaceable>label</replaceable>>> </optional>
FOR <replaceable>
record_or_row
</replaceable> IN <replaceable>query</replaceable> LOOP
FOR <replaceable>
target
</replaceable> IN <replaceable>query</replaceable> LOOP
<replaceable>statements</replaceable>
<replaceable>statements</replaceable>
END LOOP <optional> <replaceable>label</replaceable> </optional>;
END LOOP <optional> <replaceable>label</replaceable> </optional>;
</synopsis>
</synopsis>
The record or row variable is successively assigned each row
<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
resulting from the <replaceable>query</replaceable> (which must be a
<command>SELECT</command> command) and the loop body is executed for each
<command>SELECT</command> command) and the loop body is executed for each
row. Here is an example:
row. Here is an example:
...
@@ -2047,7 +2049,7 @@ $$ LANGUAGE plpgsql;
...
@@ -2047,7 +2049,7 @@ $$ LANGUAGE plpgsql;
rows:
rows:
<synopsis>
<synopsis>
<optional> <<<replaceable>label</replaceable>>> </optional>
<optional> <<<replaceable>label</replaceable>>> </optional>
FOR <replaceable>
record_or_row
</replaceable> IN EXECUTE <replaceable>text_expression</replaceable> LOOP
FOR <replaceable>
target
</replaceable> IN EXECUTE <replaceable>text_expression</replaceable> LOOP
<replaceable>statements</replaceable>
<replaceable>statements</replaceable>
END LOOP <optional> <replaceable>label</replaceable> </optional>;
END LOOP <optional> <replaceable>label</replaceable> </optional>;
</synopsis>
</synopsis>
...
@@ -2067,7 +2069,7 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
...
@@ -2067,7 +2069,7 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
<literal>IN</> and <literal>LOOP</>. If <literal>..</> is not seen then
<literal>IN</> and <literal>LOOP</>. If <literal>..</> is not seen then
the loop is presumed to be a loop over rows. Mistyping the <literal>..</>
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
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</>,
<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.
rather than the simple syntax error one might expect to get.
</para>
</para>
</note>
</note>
...
...
src/pl/plpgsql/src/gram.y
View file @
025ffe58
...
@@ -4,7 +4,7 @@
...
@@ -4,7 +4,7 @@
* procedural language
* procedural language
*
*
* IDENTIFICATION
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.8
3 2006/02/12 04:59:32 tgl
Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.8
4 2006/02/12 06:03:38 momjian
Exp $
*
*
* This software is copyrighted by Jan Wieck - Hamburg.
* This software is copyrighted by Jan Wieck - Hamburg.
*
*
...
@@ -58,7 +58,9 @@ static void check_sql_expr(const char *stmt);
...
@@ -58,7 +58,9 @@ static void check_sql_expr(const char *stmt);
static void plpgsql_sql_error_callback(void *arg);
static void plpgsql_sql_error_callback(void *arg);
static void check_labels(const char *start_label,
static void check_labels(const char *start_label,
const char *end_label);
const char *end_label);
static PLpgSQL_row *make_scalar_list1(const char *name,
PLpgSQL_datum *variable);
%}
%}
%union {
%union {
...
@@ -76,6 +78,7 @@ static void check_labels(const char *start_label,
...
@@ -76,6 +78,7 @@ static void check_labels(const char *start_label,
int lineno;
int lineno;
PLpgSQL_rec *rec;
PLpgSQL_rec *rec;
PLpgSQL_row *row;
PLpgSQL_row *row;
PLpgSQL_datum *scalar;
} forvariable;
} forvariable;
struct
struct
{
{
...
@@ -890,10 +893,15 @@ for_control :
...
@@ -890,10 +893,15 @@ for_control :
new->row = $2.row;
new->row = $2.row;
check_assignable((PLpgSQL_datum *) new->row);
check_assignable((PLpgSQL_datum *) new->row);
}
}
else if ($2.scalar)
{
new->row = make_scalar_list1($2.name, $2.scalar);
check_assignable((PLpgSQL_datum *) new->row);
}
else
else
{
{
plpgsql_error_lineno = $1;
plpgsql_error_lineno = $1;
yyerror("loop variable of loop over rows must be a record
or row
variable");
yyerror("loop variable of loop over rows must be a record
, row, or scalar
variable");
}
}
new->query = expr;
new->query = expr;
...
@@ -948,6 +956,15 @@ for_control :
...
@@ -948,6 +956,15 @@ for_control :
expr2 = plpgsql_read_expression(K_LOOP, "LOOP");
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;
}
/* create loop's private variable */
/* create loop's private variable */
fvar = (PLpgSQL_var *)
fvar = (PLpgSQL_var *)
plpgsql_build_variable($2.name,
plpgsql_build_variable($2.name,
...
@@ -1002,10 +1019,15 @@ for_control :
...
@@ -1002,10 +1019,15 @@ for_control :
new->row = $2.row;
new->row = $2.row;
check_assignable((PLpgSQL_datum *) new->row);
check_assignable((PLpgSQL_datum *) new->row);
}
}
else if ($2.scalar)
{
new->row = make_scalar_list1($2.name, $2.scalar);
check_assignable((PLpgSQL_datum *) new->row);
}
else
else
{
{
plpgsql_error_lineno = $1;
plpgsql_error_lineno = $1;
yyerror("loop variable of loop over rows must be record
or row
variable");
yyerror("loop variable of loop over rows must be record
, row, or scalar
variable");
}
}
new->query = expr1;
new->query = expr1;
...
@@ -1027,14 +1049,31 @@ for_control :
...
@@ -1027,14 +1049,31 @@ for_control :
* until we know what's what.
* until we know what's what.
*/
*/
for_variable : T_SCALAR
for_variable : T_SCALAR
{
{
int tok;
char *name;
char *name;
name = pstrdup(yytext);
$$.scalar = yylval.scalar;
$$.lineno = plpgsql_scanner_lineno();
plpgsql_convert_ident(yytext, &name, 1);
if((tok = yylex()) == ',')
$$.name = name;
{
$$.lineno = plpgsql_scanner_lineno();
plpgsql_push_back_token(tok);
$$.rec = NULL;
$$.name = NULL;
$$.row = 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
| T_WORD
{
{
...
@@ -1048,20 +1087,14 @@ for_variable : T_SCALAR
...
@@ -1048,20 +1087,14 @@ for_variable : T_SCALAR
}
}
| T_RECORD
| T_RECORD
{
{
char *name;
$$.name = NULL;
plpgsql_convert_ident(yytext, &name, 1);
$$.name = name;
$$.lineno = plpgsql_scanner_lineno();
$$.lineno = plpgsql_scanner_lineno();
$$.rec = yylval.rec;
$$.rec = yylval.rec;
$$.row = NULL;
$$.row = NULL;
}
}
| T_ROW
| T_ROW
{
{
char *name;
$$.name = NULL;
plpgsql_convert_ident(yytext, &name, 1);
$$.name = name;
$$.lineno = plpgsql_scanner_lineno();
$$.lineno = plpgsql_scanner_lineno();
$$.row = yylval.row;
$$.row = yylval.row;
$$.rec = NULL;
$$.rec = NULL;
...
@@ -2088,6 +2121,30 @@ make_fetch_stmt(void)
...
@@ -2088,6 +2121,30 @@ make_fetch_stmt(void)
}
}
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
static void
check_assignable(PLpgSQL_datum *datum)
check_assignable(PLpgSQL_datum *datum)
{
{
...
...
src/test/regress/expected/plpgsql.out
View file @
025ffe58
...
@@ -2721,3 +2721,23 @@ end;
...
@@ -2721,3 +2721,23 @@ end;
$$ language plpgsql;
$$ language plpgsql;
ERROR: end label "outer_label" specified for unlabelled block
ERROR: end label "outer_label" specified for unlabelled block
CONTEXT: compile of PL/pgSQL function "end_label4" near line 5
CONTEXT: compile of PL/pgSQL function "end_label4" near line 5
-- 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;
src/test/regress/sql/plpgsql.sql
View file @
025ffe58
...
@@ -2280,3 +2280,25 @@ begin
...
@@ -2280,3 +2280,25 @@ begin
end
loop
outer_label
;
end
loop
outer_label
;
end
;
end
;
$$
language
plpgsql
;
$$
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
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment