Add BY clause to PL/PgSQL FOR loop, to control the iteration increment.
Jaime Casanova
This commit is contained in:
parent
e6a7b01930
commit
07c25723da
@ -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">
|
<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;
|
|||||||
|
|
||||||
<synopsis>
|
<synopsis>
|
||||||
<optional> <<<replaceable>label</replaceable>>> </optional>
|
<optional> <<<replaceable>label</replaceable>>> </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>;
|
|||||||
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;
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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,
|
|||||||
%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 :
|
|||||||
{
|
{
|
||||||
/* 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 :
|
|||||||
/* 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 :
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
|
|
||||||
/* ----------
|
/* ----------
|
||||||
* 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)
|
|||||||
{
|
{
|
||||||
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)
|
|||||||
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)
|
|||||||
* 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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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)
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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
|
|||||||
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 @@
|
|||||||
*
|
*
|
||||||
*
|
*
|
||||||
* 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 [^$]+
|
|||||||
\.\. { 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; }
|
||||||
|
Loading…
x
Reference in New Issue
Block a user