Commit 07c25723 authored by Bruce Momjian's avatar Bruce Momjian

Add BY clause to PL/PgSQL FOR loop, to control the iteration increment.

Jaime Casanova
parent e6a7b019
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.94 2006/05/30 13:40:55 momjian Exp $ -->
<!-- $PostgreSQL: pgsql/doc/src/sgml/plpgsql.sgml,v 1.95 2006/06/12 16:45:30 momjian Exp $ -->
<chapter id="plpgsql">
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
......@@ -1975,7 +1975,7 @@ END LOOP;
<synopsis>
<optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional>
FOR <replaceable>name</replaceable> IN <optional> REVERSE </optional> <replaceable>expression</replaceable> .. <replaceable>expression</replaceable> LOOP
FOR <replaceable>name</replaceable> IN <optional> REVERSE </optional> <replaceable>expression</replaceable> .. <replaceable>expression</replaceable> <optional> BY <replaceable>expression</replaceable> </optional> LOOP
<replaceable>statements</replaceable>
END LOOP <optional> <replaceable>label</replaceable> </optional>;
</synopsis>
......@@ -1988,8 +1988,10 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
definition of the variable name is ignored within the loop).
The two expressions giving
the lower and upper bound of the range are evaluated once when entering
the loop. The iteration step is normally 1, but is -1 when <literal>REVERSE</> is
specified.
the loop. If the <literal>BY</> clause isn't specified the iteration
step is 1 otherwise it's the value specified in the <literal>BY</>
clause. If <literal>REVERSE</> is specified then the step value is
considered negative.
</para>
<para>
......@@ -2003,6 +2005,11 @@ END LOOP;
FOR i IN REVERSE 10..1 LOOP
-- some computations here
END LOOP;
FOR i IN REVERSE 10..1 BY 2 LOOP
-- some computations here
RAISE NOTICE 'i is %', i;
END LOOP;
</programlisting>
</para>
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.90 2006/05/27 19:45:52 tgl Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.91 2006/06/12 16:45:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -144,6 +144,7 @@ static void check_labels(const char *start_label,
%token K_ALIAS
%token K_ASSIGN
%token K_BEGIN
%token K_BY
%token K_CLOSE
%token K_CONSTANT
%token K_CONTINUE
......@@ -935,6 +936,7 @@ for_control :
{
/* Saw "..", so it must be an integer loop */
PLpgSQL_expr *expr2;
PLpgSQL_expr *expr_by;
PLpgSQL_var *fvar;
PLpgSQL_stmt_fori *new;
char *varname;
......@@ -942,7 +944,34 @@ for_control :
/* First expression is well-formed */
check_sql_expr(expr1->query);
expr2 = plpgsql_read_expression(K_LOOP, "LOOP");
expr2 = read_sql_construct(K_BY,
K_LOOP,
"LOOP",
"SELECT ",
true,
false,
&tok);
if (tok == K_BY)
expr_by = plpgsql_read_expression(K_LOOP, "LOOP");
else
{
/*
* If there is no BY clause we will assume 1
*/
char buf[1024];
PLpgSQL_dstring ds;
plpgsql_dstring_init(&ds);
expr_by = palloc0(sizeof(PLpgSQL_expr));
expr_by->dtype = PLPGSQL_DTYPE_EXPR;
strcpy(buf, "SELECT 1");
plpgsql_dstring_append(&ds, buf);
expr_by->query = pstrdup(plpgsql_dstring_get(&ds));
expr_by->plan = NULL;
}
/* should have had a single variable name */
plpgsql_error_lineno = $2.lineno;
......@@ -970,6 +999,7 @@ for_control :
new->reverse = reverse;
new->lower = expr1;
new->upper = expr2;
new->by = expr_by;
$$ = (PLpgSQL_stmt *) new;
}
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.169 2006/05/30 13:40:55 momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.170 2006/06/12 16:45:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -1361,7 +1361,8 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
/* ----------
* exec_stmt_fori Iterate an integer variable
* from a lower to an upper value.
* from a lower to an upper value
* incrementing or decrementing in BY value
* Loop can be left with exit.
* ----------
*/
......@@ -1370,6 +1371,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
{
PLpgSQL_var *var;
Datum value;
Datum by_value;
Oid valtype;
bool isnull;
bool found = false;
......@@ -1407,6 +1409,21 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
errmsg("upper bound of FOR loop cannot be NULL")));
exec_eval_cleanup(estate);
/*
* Get the by value
*/
by_value = exec_eval_expr(estate, stmt->by, &isnull, &valtype);
by_value = exec_cast_value(by_value, valtype, var->datatype->typoid,
&(var->datatype->typinput),
var->datatype->typioparam,
var->datatype->atttypmod, isnull);
if (isnull)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
errmsg("by value of FOR loop cannot be NULL")));
exec_eval_cleanup(estate);
/*
* Now do the loop
*/
......@@ -1483,9 +1500,9 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
* Increase/decrease loop var
*/
if (stmt->reverse)
var->value--;
var->value -= by_value;
else
var->value++;
var->value += by_value;
}
/*
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.52 2006/05/30 13:40:55 momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.53 2006/06/12 16:45:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -705,6 +705,10 @@ dump_fori(PLpgSQL_stmt_fori *stmt)
printf(" upper = ");
dump_expr(stmt->upper);
printf("\n");
dump_ind();
printf(" by = ");
dump_expr(stmt->by);
printf("\n");
dump_indent -= 2;
dump_stmts(stmt->body);
......
......@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.74 2006/05/30 13:40:55 momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.75 2006/06/12 16:45:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -398,6 +398,7 @@ typedef struct
PLpgSQL_var *var;
PLpgSQL_expr *lower;
PLpgSQL_expr *upper;
PLpgSQL_expr *by;
int reverse;
List *body; /* List of statements */
} PLpgSQL_stmt_fori;
......
......@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.49 2006/05/30 13:40:55 momjian Exp $
* $PostgreSQL: pgsql/src/pl/plpgsql/src/scan.l,v 1.50 2006/06/12 16:45:30 momjian Exp $
*
*-------------------------------------------------------------------------
*/
......@@ -116,6 +116,7 @@ dolqinside [^$]+
\.\. { return K_DOTDOT; }
alias { return K_ALIAS; }
begin { return K_BEGIN; }
by { return K_BY; }
close { return K_CLOSE; }
constant { return K_CONSTANT; }
continue { return K_CONTINUE; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment