Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 07c2572

Browse files
committed
Add BY clause to PL/PgSQL FOR loop, to control the iteration increment.
Jaime Casanova
1 parent e6a7b01 commit 07c2572

File tree

6 files changed

+73
-13
lines changed

6 files changed

+73
-13
lines changed

doc/src/sgml/plpgsql.sgml

+11-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.94 2006/05/30 13:40:55 momjian Exp $ -->
1+
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.95 2006/06/12 16:45:30 momjian Exp $ -->
22

33
<chapter id="plpgsql">
44
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
@@ -1975,7 +1975,7 @@ END LOOP;
19751975

19761976
<synopsis>
19771977
<optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
1978-
FOR <replaceable>name</replaceable> IN <optional> REVERSE </optional> <replaceable>expression</replaceable> .. <replaceable>expression</replaceable> LOOP
1978+
FOR <replaceable>name</replaceable> IN <optional> REVERSE </optional> <replaceable>expression</replaceable> .. <replaceable>expression</replaceable> <optional> BY <replaceable>expression</replaceable> </optional> LOOP
19791979
<replaceable>statements</replaceable>
19801980
END LOOP <optional> <replaceable>label</replaceable> </optional>;
19811981
</synopsis>
@@ -1988,8 +1988,10 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
19881988
definition of the variable name is ignored within the loop).
19891989
The two expressions giving
19901990
the lower and upper bound of the range are evaluated once when entering
1991-
the loop. The iteration step is normally 1, but is -1 when <literal>REVERSE</> is
1992-
specified.
1991+
the loop. If the <literal>BY</> clause isn't specified the iteration
1992+
step is 1 otherwise it's the value specified in the <literal>BY</>
1993+
clause. If <literal>REVERSE</> is specified then the step value is
1994+
considered negative.
19931995
</para>
19941996

19951997
<para>
@@ -2003,6 +2005,11 @@ END LOOP;
20032005
FOR i IN REVERSE 10..1 LOOP
20042006
-- some computations here
20052007
END LOOP;
2008+
2009+
FOR i IN REVERSE 10..1 BY 2 LOOP
2010+
-- some computations here
2011+
RAISE NOTICE 'i is %', i;
2012+
END LOOP;
20062013
</programlisting>
20072014
</para>
20082015

src/pl/plpgsql/src/gram.y

+32-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.90 2006/05/27 19:45:52 tgl Exp $
12+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.91 2006/06/12 16:45:30 momjian Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -144,6 +144,7 @@ static void check_labels(const char *start_label,
144144
%token K_ALIAS
145145
%token K_ASSIGN
146146
%token K_BEGIN
147+
%token K_BY
147148
%token K_CLOSE
148149
%token K_CONSTANT
149150
%token K_CONTINUE
@@ -935,14 +936,42 @@ for_control :
935936
{
936937
/* Saw "..", so it must be an integer loop */
937938
PLpgSQL_expr *expr2;
939+
PLpgSQL_expr *expr_by;
938940
PLpgSQL_var *fvar;
939941
PLpgSQL_stmt_fori *new;
940942
char *varname;
941943

942944
/* First expression is well-formed */
943945
check_sql_expr(expr1->query);
944946

945-
expr2 = plpgsql_read_expression(K_LOOP, "LOOP");
947+
948+
expr2 = read_sql_construct(K_BY,
949+
K_LOOP,
950+
"LOOP",
951+
"SELECT ",
952+
true,
953+
false,
954+
&tok);
955+
956+
if (tok == K_BY)
957+
expr_by = plpgsql_read_expression(K_LOOP, "LOOP");
958+
else
959+
{
960+
/*
961+
* If there is no BY clause we will assume 1
962+
*/
963+
char buf[1024];
964+
PLpgSQL_dstring ds;
965+
966+
plpgsql_dstring_init(&ds);
967+
968+
expr_by = palloc0(sizeof(PLpgSQL_expr));
969+
expr_by->dtype = PLPGSQL_DTYPE_EXPR;
970+
strcpy(buf, "SELECT 1");
971+
plpgsql_dstring_append(&ds, buf);
972+
expr_by->query = pstrdup(plpgsql_dstring_get(&ds));
973+
expr_by->plan = NULL;
974+
}
946975

947976
/* should have had a single variable name */
948977
plpgsql_error_lineno = $2.lineno;
@@ -970,6 +999,7 @@ for_control :
970999
new->reverse = reverse;
9711000
new->lower = expr1;
9721001
new->upper = expr2;
1002+
new->by = expr_by;
9731003

9741004
$$ = (PLpgSQL_stmt *) new;
9751005
}

src/pl/plpgsql/src/pl_exec.c

+21-4
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.169 2006/05/30 13:40:55 momjian Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.170 2006/06/12 16:45:30 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1361,7 +1361,8 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
13611361

13621362
/* ----------
13631363
* exec_stmt_fori Iterate an integer variable
1364-
* from a lower to an upper value.
1364+
* from a lower to an upper value
1365+
* incrementing or decrementing in BY value
13651366
* Loop can be left with exit.
13661367
* ----------
13671368
*/
@@ -1370,6 +1371,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
13701371
{
13711372
PLpgSQL_var *var;
13721373
Datum value;
1374+
Datum by_value;
13731375
Oid valtype;
13741376
bool isnull;
13751377
bool found = false;
@@ -1407,6 +1409,21 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
14071409
errmsg("upper bound of FOR loop cannot be NULL")));
14081410
exec_eval_cleanup(estate);
14091411

1412+
/*
1413+
* Get the by value
1414+
*/
1415+
by_value = exec_eval_expr(estate, stmt->by, &isnull, &valtype);
1416+
by_value = exec_cast_value(by_value, valtype, var->datatype->typoid,
1417+
&(var->datatype->typinput),
1418+
var->datatype->typioparam,
1419+
var->datatype->atttypmod, isnull);
1420+
1421+
if (isnull)
1422+
ereport(ERROR,
1423+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1424+
errmsg("by value of FOR loop cannot be NULL")));
1425+
exec_eval_cleanup(estate);
1426+
14101427
/*
14111428
* Now do the loop
14121429
*/
@@ -1483,9 +1500,9 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
14831500
* Increase/decrease loop var
14841501
*/
14851502
if (stmt->reverse)
1486-
var->value--;
1503+
var->value -= by_value;
14871504
else
1488-
var->value++;
1505+
var->value += by_value;
14891506
}
14901507

14911508
/*

src/pl/plpgsql/src/pl_funcs.c

+5-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.52 2006/05/30 13:40:55 momjian Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.53 2006/06/12 16:45:30 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -705,6 +705,10 @@ dump_fori(PLpgSQL_stmt_fori *stmt)
705705
printf(" upper = ");
706706
dump_expr(stmt->upper);
707707
printf("\n");
708+
dump_ind();
709+
printf(" by = ");
710+
dump_expr(stmt->by);
711+
printf("\n");
708712
dump_indent -= 2;
709713

710714
dump_stmts(stmt->body);

src/pl/plpgsql/src/plpgsql.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.74 2006/05/30 13:40:55 momjian Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.75 2006/06/12 16:45:30 momjian Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -398,6 +398,7 @@ typedef struct
398398
PLpgSQL_var *var;
399399
PLpgSQL_expr *lower;
400400
PLpgSQL_expr *upper;
401+
PLpgSQL_expr *by;
401402
int reverse;
402403
List *body; /* List of statements */
403404
} PLpgSQL_stmt_fori;

src/pl/plpgsql/src/scan.l

+2-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.49 2006/05/30 13:40:55 momjian Exp $
12+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.50 2006/06/12 16:45:30 momjian Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -116,6 +116,7 @@ dolqinside [^$]+
116116
\.\. { return K_DOTDOT; }
117117
alias { return K_ALIAS; }
118118
begin { return K_BEGIN; }
119+
by { return K_BY; }
119120
close { return K_CLOSE; }
120121
constant { return K_CONSTANT; }
121122
continue { return K_CONTINUE; }

0 commit comments

Comments
 (0)