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"> <chapter id="plpgsql">
<title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title> <title><application>PL/pgSQL</application> - <acronym>SQL</acronym> Procedural Language</title>
...@@ -1975,7 +1975,7 @@ END LOOP; ...@@ -1975,7 +1975,7 @@ END LOOP;
<synopsis> <synopsis>
<optional> &lt;&lt;<replaceable>label</replaceable>&gt;&gt; </optional> <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> <replaceable>statements</replaceable>
END LOOP <optional> <replaceable>label</replaceable> </optional>; END LOOP <optional> <replaceable>label</replaceable> </optional>;
</synopsis> </synopsis>
...@@ -1988,8 +1988,10 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>; ...@@ -1988,8 +1988,10 @@ END LOOP <optional> <replaceable>label</replaceable> </optional>;
definition of the variable name is ignored within the loop). definition of the variable name is ignored within the loop).
The two expressions giving The two expressions giving
the lower and upper bound of the range are evaluated once when entering 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 the loop. If the <literal>BY</> clause isn't specified the iteration
specified. 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>
<para> <para>
...@@ -2003,6 +2005,11 @@ END LOOP; ...@@ -2003,6 +2005,11 @@ END LOOP;
FOR i IN REVERSE 10..1 LOOP FOR i IN REVERSE 10..1 LOOP
-- some computations here -- some computations here
END LOOP; END LOOP;
FOR i IN REVERSE 10..1 BY 2 LOOP
-- some computations here
RAISE NOTICE 'i is %', i;
END LOOP;
</programlisting> </programlisting>
</para> </para>
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -144,6 +144,7 @@ static void check_labels(const char *start_label,
%token K_ALIAS %token K_ALIAS
%token K_ASSIGN %token K_ASSIGN
%token K_BEGIN %token K_BEGIN
%token K_BY
%token K_CLOSE %token K_CLOSE
%token K_CONSTANT %token K_CONSTANT
%token K_CONTINUE %token K_CONTINUE
...@@ -935,6 +936,7 @@ for_control : ...@@ -935,6 +936,7 @@ for_control :
{ {
/* Saw "..", so it must be an integer loop */ /* Saw "..", so it must be an integer loop */
PLpgSQL_expr *expr2; PLpgSQL_expr *expr2;
PLpgSQL_expr *expr_by;
PLpgSQL_var *fvar; PLpgSQL_var *fvar;
PLpgSQL_stmt_fori *new; PLpgSQL_stmt_fori *new;
char *varname; char *varname;
...@@ -942,7 +944,34 @@ for_control : ...@@ -942,7 +944,34 @@ for_control :
/* First expression is well-formed */ /* First expression is well-formed */
check_sql_expr(expr1->query); 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 */ /* should have had a single variable name */
plpgsql_error_lineno = $2.lineno; plpgsql_error_lineno = $2.lineno;
...@@ -970,6 +999,7 @@ for_control : ...@@ -970,6 +999,7 @@ for_control :
new->reverse = reverse; new->reverse = reverse;
new->lower = expr1; new->lower = expr1;
new->upper = expr2; new->upper = expr2;
new->by = expr_by;
$$ = (PLpgSQL_stmt *) new; $$ = (PLpgSQL_stmt *) new;
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1361,7 +1361,8 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
/* ---------- /* ----------
* exec_stmt_fori Iterate an integer variable * 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. * Loop can be left with exit.
* ---------- * ----------
*/ */
...@@ -1370,6 +1371,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt) ...@@ -1370,6 +1371,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
{ {
PLpgSQL_var *var; PLpgSQL_var *var;
Datum value; Datum value;
Datum by_value;
Oid valtype; Oid valtype;
bool isnull; bool isnull;
bool found = false; bool found = false;
...@@ -1407,6 +1409,21 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt) ...@@ -1407,6 +1409,21 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
errmsg("upper bound of FOR loop cannot be NULL"))); errmsg("upper bound of FOR loop cannot be NULL")));
exec_eval_cleanup(estate); 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 * Now do the loop
*/ */
...@@ -1483,9 +1500,9 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt) ...@@ -1483,9 +1500,9 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
* Increase/decrease loop var * Increase/decrease loop var
*/ */
if (stmt->reverse) if (stmt->reverse)
var->value--; var->value -= by_value;
else else
var->value++; var->value += by_value;
} }
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -705,6 +705,10 @@ dump_fori(PLpgSQL_stmt_fori *stmt)
printf(" upper = "); printf(" upper = ");
dump_expr(stmt->upper); dump_expr(stmt->upper);
printf("\n"); printf("\n");
dump_ind();
printf(" by = ");
dump_expr(stmt->by);
printf("\n");
dump_indent -= 2; dump_indent -= 2;
dump_stmts(stmt->body); dump_stmts(stmt->body);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 ...@@ -398,6 +398,7 @@ typedef struct
PLpgSQL_var *var; PLpgSQL_var *var;
PLpgSQL_expr *lower; PLpgSQL_expr *lower;
PLpgSQL_expr *upper; PLpgSQL_expr *upper;
PLpgSQL_expr *by;
int reverse; int reverse;
List *body; /* List of statements */ List *body; /* List of statements */
} PLpgSQL_stmt_fori; } PLpgSQL_stmt_fori;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* *
* *
* IDENTIFICATION * 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 [^$]+ ...@@ -116,6 +116,7 @@ dolqinside [^$]+
\.\. { return K_DOTDOT; } \.\. { return K_DOTDOT; }
alias { return K_ALIAS; } alias { return K_ALIAS; }
begin { return K_BEGIN; } begin { return K_BEGIN; }
by { return K_BY; }
close { return K_CLOSE; } close { return K_CLOSE; }
constant { return K_CONSTANT; } constant { return K_CONSTANT; }
continue { return K_CONTINUE; } 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