aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/src/sgml/plpgsql.sgml15
-rw-r--r--src/pl/plpgsql/src/gram.y34
-rw-r--r--src/pl/plpgsql/src/pl_exec.c25
-rw-r--r--src/pl/plpgsql/src/pl_funcs.c6
-rw-r--r--src/pl/plpgsql/src/plpgsql.h3
-rw-r--r--src/pl/plpgsql/src/scan.l3
6 files changed, 73 insertions, 13 deletions
diff --git a/doc/src/sgml/plpgsql.sgml b/doc/src/sgml/plpgsql.sgml
index f0cbbf2896c..60c7593362b 100644
--- a/doc/src/sgml/plpgsql.sgml
+++ b/doc/src/sgml/plpgsql.sgml
@@ -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>
diff --git a/src/pl/plpgsql/src/gram.y b/src/pl/plpgsql/src/gram.y
index 2461deaf328..5343dfb1978 100644
--- a/src/pl/plpgsql/src/gram.y
+++ b/src/pl/plpgsql/src/gram.y
@@ -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;
}
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index b27849c8913..3ac48bbcecb 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -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;
@@ -1408,6 +1410,21 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
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
*/
for (;;)
@@ -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;
}
/*
diff --git a/src/pl/plpgsql/src/pl_funcs.c b/src/pl/plpgsql/src/pl_funcs.c
index 9420ab15cf3..a4e661a44af 100644
--- a/src/pl/plpgsql/src/pl_funcs.c
+++ b/src/pl/plpgsql/src/pl_funcs.c
@@ -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);
diff --git a/src/pl/plpgsql/src/plpgsql.h b/src/pl/plpgsql/src/plpgsql.h
index 86fea3ca465..16ffe7e93df 100644
--- a/src/pl/plpgsql/src/plpgsql.h
+++ b/src/pl/plpgsql/src/plpgsql.h
@@ -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;
diff --git a/src/pl/plpgsql/src/scan.l b/src/pl/plpgsql/src/scan.l
index dfc2b942ecb..daafe96b874 100644
--- a/src/pl/plpgsql/src/scan.l
+++ b/src/pl/plpgsql/src/scan.l
@@ -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; }