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

Jaime Casanova
This commit is contained in:
Bruce Momjian 2006-06-12 16:45:30 +00:00
parent e6a7b01930
commit 07c25723da
6 changed files with 73 additions and 13 deletions

View File

@ -1,4 +1,4 @@
<!-- $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>

View File

@ -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;
}

View File

@ -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;
}
/*

View File

@ -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);

View File

@ -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;

View File

@ -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; }