On 4/30/06, Jaime Casanova <[EMAIL PROTECTED]> wrote:
On 4/29/06, Andrew Dunstan <[EMAIL PROTECTED]> wrote:
> Tom Lane wrote:
>
> >"Jaime Casanova" <[EMAIL PROTECTED]> writes:
> >
> >
> >>there is a chance to add a STEP clause to the FOR statement in plpgsql?
> >>
> >>
> >
> >This is not free: it'd require making STEP a reserved word (at least
> >within plpgsql) which is contrary to spec. I think you need to make
> >a pretty good case why the value of the feature outweighs breaking
> >applications that have perfectly-legally used "step" as an identifier.
> >
> >
>
> This isn't available in PL/SQL, is it? That doesn't mean we shouldn't do it,
of course, but it might lessen any perceived imperative.
>
> Maybe using BY instad of STEP as the keyword would make it easier, since its
occurrence in SQL makes it less likely to be used as a variable.
>
> cheers
>
> andrew
>
>
Hi,
i make a little patch using BY instead of STEP per Tom's complaint and
Andrew's suggestion.
the patch is ready, at least it seems to me... also i have added some
lines to the docs...
let me know what your decision is about this...
--
regards,
Jaime Casanova
"Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs and the universe trying
to produce bigger and better idiots.
So far, the universe is winning."
Richard Cook
diff -rcEib pgsql-8.2dev/doc/src/sgml/plpgsql.sgml pgsql-8.2fori/doc/src/sgml/plpgsql.sgml
*** pgsql-8.2dev/doc/src/sgml/plpgsql.sgml 2006-05-01 08:49:20.000000000 -0500
--- pgsql-8.2fori/doc/src/sgml/plpgsql.sgml 2006-05-05 17:31:36.000000000 -0500
***************
*** 1960,1966 ****
<synopsis>
<optional> <<<replaceable>label</replaceable>>> </optional>
! FOR <replaceable>name</replaceable> IN <optional> REVERSE </optional> <replaceable>expression</replaceable> .. <replaceable>expression</replaceable> LOOP
<replaceable>statements</replaceable>
END LOOP <optional> <replaceable>label</replaceable> </optional>;
</synopsis>
--- 1960,1966 ----
<synopsis>
<optional> <<<replaceable>label</replaceable>>> </optional>
! 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>
***************
*** 1973,1980 ****
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.
</para>
<para>
--- 1973,1982 ----
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. 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>
***************
*** 1988,1993 ****
--- 1990,2000 ----
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 -rcEib pgsql-8.2dev/src/pl/plpgsql/src/gram.y pgsql-8.2fori/src/pl/plpgsql/src/gram.y
*** pgsql-8.2dev/src/pl/plpgsql/src/gram.y 2006-05-01 08:49:39.000000000 -0500
--- pgsql-8.2fori/src/pl/plpgsql/src/gram.y 2006-05-05 17:42:08.000000000 -0500
***************
*** 143,148 ****
--- 143,149 ----
%token K_ALIAS
%token K_ASSIGN
%token K_BEGIN
+ %token K_BY
%token K_CLOSE
%token K_CONSTANT
%token K_CONTINUE
***************
*** 930,935 ****
--- 931,937 ----
{
/* Saw "..", so it must be an integer loop */
PLpgSQL_expr *expr2;
+ PLpgSQL_expr *expr_by;
PLpgSQL_var *fvar;
PLpgSQL_stmt_fori *new;
char *varname;
***************
*** 937,943 ****
/* First expression is well-formed */
check_sql_expr(expr1->query);
! expr2 = plpgsql_read_expression(K_LOOP, "LOOP");
/* should have had a single variable name */
plpgsql_error_lineno = $2.lineno;
--- 939,968 ----
/* First expression is well-formed */
check_sql_expr(expr1->query);
!
! 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];
!
! expr_by = palloc0(sizeof(PLpgSQL_expr));
! expr_by->dtype = PLPGSQL_DTYPE_EXPR;
! strcpy(buf, "SELECT 1");
! expr_by->query = buf;
! expr_by->plan = NULL;
! }
/* should have had a single variable name */
plpgsql_error_lineno = $2.lineno;
***************
*** 965,970 ****
--- 990,996 ----
new->reverse = reverse;
new->lower = expr1;
new->upper = expr2;
+ new->by = expr_by;
$$ = (PLpgSQL_stmt *) new;
}
diff -rcEib pgsql-8.2dev/src/pl/plpgsql/src/pl_exec.c pgsql-8.2fori/src/pl/plpgsql/src/pl_exec.c
*** pgsql-8.2dev/src/pl/plpgsql/src/pl_exec.c 2006-05-01 08:49:39.000000000 -0500
--- pgsql-8.2fori/src/pl/plpgsql/src/pl_exec.c 2006-05-05 18:18:23.000000000 -0500
***************
*** 1346,1352 ****
/* ----------
* exec_stmt_fori Iterate an integer variable
! * from a lower to an upper value.
* Loop can be left with exit.
* ----------
*/
--- 1346,1353 ----
/* ----------
* exec_stmt_fori Iterate an integer variable
! * from a lower to an upper value
! * incrementing or decrementing in BY value
* Loop can be left with exit.
* ----------
*/
***************
*** 1355,1360 ****
--- 1356,1362 ----
{
PLpgSQL_var *var;
Datum value;
+ Datum by_value;
Oid valtype;
bool isnull;
bool found = false;
***************
*** 1393,1398 ****
--- 1395,1415 ----
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 (;;)
***************
*** 1468,1476 ****
* Increase/decrease loop var
*/
if (stmt->reverse)
! var->value--;
else
! var->value++;
}
/*
--- 1485,1493 ----
* Increase/decrease loop var
*/
if (stmt->reverse)
! var->value -= by_value;
else
! var->value += by_value;
}
/*
diff -rcEib pgsql-8.2dev/src/pl/plpgsql/src/pl_funcs.c pgsql-8.2fori/src/pl/plpgsql/src/pl_funcs.c
*** pgsql-8.2dev/src/pl/plpgsql/src/pl_funcs.c 2006-05-01 08:49:39.000000000 -0500
--- pgsql-8.2fori/src/pl/plpgsql/src/pl_funcs.c 2006-05-05 17:48:53.000000000 -0500
***************
*** 705,710 ****
--- 705,714 ----
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 -rcEib pgsql-8.2dev/src/pl/plpgsql/src/plpgsql.h pgsql-8.2fori/src/pl/plpgsql/src/plpgsql.h
*** pgsql-8.2dev/src/pl/plpgsql/src/plpgsql.h 2006-05-01 08:49:39.000000000 -0500
--- pgsql-8.2fori/src/pl/plpgsql/src/plpgsql.h 2006-04-30 09:49:39.000000000 -0500
***************
*** 398,403 ****
--- 398,404 ----
PLpgSQL_var *var;
PLpgSQL_expr *lower;
PLpgSQL_expr *upper;
+ PLpgSQL_expr *by;
int reverse;
List *body; /* List of statements */
} PLpgSQL_stmt_fori;
diff -rcEib pgsql-8.2dev/src/pl/plpgsql/src/scan.l pgsql-8.2fori/src/pl/plpgsql/src/scan.l
*** pgsql-8.2dev/src/pl/plpgsql/src/scan.l 2006-05-01 08:49:39.000000000 -0500
--- pgsql-8.2fori/src/pl/plpgsql/src/scan.l 2006-04-30 09:49:25.000000000 -0500
***************
*** 116,121 ****
--- 116,122 ----
\.\. { 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; }
---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?
http://www.postgresql.org/docs/faq