Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit816ff27

Browse files
committed
Reject zero or negative BY step in plpgsql integer FOR-loops, and behave
sanely if the loop value overflows int32 on the way to the end value.Avoid useless computation of "SELECT 1" when BY is omitted. Avoid sometype-punning between Datum and int4 that dates from the original coding.
1 parenta69f902 commit816ff27

File tree

4 files changed

+68
-58
lines changed

4 files changed

+68
-58
lines changed

‎src/pl/plpgsql/src/gram.y

Lines changed: 11 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
*
1010
*
1111
* IDENTIFICATION
12-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.102 2007/04/29 01:21:09 neilc Exp $
12+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.103 2007/07/15 02:15:04 tgl Exp $
1313
*
1414
*-------------------------------------------------------------------------
1515
*/
@@ -876,7 +876,7 @@ stmt_for: opt_block_label K_FOR for_control loop_body
876876
}
877877

878878
check_labels($1, $4.end_label);
879-
/* close namespace started inopt_label*/
879+
/* close namespace started inopt_block_label*/
880880
plpgsql_ns_pop();
881881
}
882882
;
@@ -968,39 +968,25 @@ for_control:
968968
PLpgSQL_stmt_fori*new;
969969
char*varname;
970970

971-
/*First expression is well-formed*/
971+
/*Check first expression is well-formed*/
972972
check_sql_expr(expr1->query);
973973

974-
975-
expr2 = read_sql_construct(K_BY,
976-
K_LOOP,
974+
/* Read and check the second one*/
975+
expr2 = read_sql_construct(K_LOOP,
976+
K_BY,
977977
"LOOP",
978978
"SELECT",
979979
true,
980-
false,
980+
true,
981981
&tok);
982982

983+
/* Get the BY clause if any*/
983984
if (tok == K_BY)
984985
expr_by = plpgsql_read_expression(K_LOOP,"LOOP");
985986
else
986-
{
987-
/*
988-
* If there is no BY clause we will assume 1
989-
*/
990-
char buf[1024];
991-
PLpgSQL_dstringds;
992-
993-
plpgsql_dstring_init(&ds);
994-
995-
expr_by = palloc0(sizeof(PLpgSQL_expr));
996-
expr_by->dtype = PLPGSQL_DTYPE_EXPR;
997-
strcpy(buf,"SELECT 1");
998-
plpgsql_dstring_append(&ds, buf);
999-
expr_by->query = pstrdup(plpgsql_dstring_get(&ds));
1000-
expr_by->plan=NULL;
1001-
}
987+
expr_by =NULL;
1002988

1003-
/*should have had a single variable name*/
989+
/*Should have had a single variable name*/
1004990
plpgsql_error_lineno =$2.lineno;
1005991
if ($2.scalar &&$2.row)
1006992
ereport(ERROR,
@@ -1023,7 +1009,7 @@ for_control:
10231009
new->reverse = reverse;
10241010
new->lower = expr1;
10251011
new->upper = expr2;
1026-
new->by = expr_by;
1012+
new->step = expr_by;
10271013

10281014
$$ = (PLpgSQL_stmt *)new;
10291015
}

‎src/pl/plpgsql/src/pl_exec.c

Lines changed: 52 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.197 2007/06/05 21:31:08 tgl Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.198 2007/07/15 02:15:04 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1517,25 +1517,26 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
15171517
/* ----------
15181518
* exec_stmt_foriIterate an integer variable
15191519
*from a lower to an upper value
1520-
*incrementing or decrementing in BY value
1521-
*Loop can be left with exit.
1520+
*incrementing or decrementing by the BY value
15221521
* ----------
15231522
*/
15241523
staticint
15251524
exec_stmt_fori(PLpgSQL_execstate*estate,PLpgSQL_stmt_fori*stmt)
15261525
{
15271526
PLpgSQL_var*var;
15281527
Datumvalue;
1529-
Datumby_value;
1530-
Oidvaltype;
15311528
boolisnull;
1529+
Oidvaltype;
1530+
int32loop_value;
1531+
int32end_value;
1532+
int32step_value;
15321533
boolfound= false;
15331534
intrc=PLPGSQL_RC_OK;
15341535

15351536
var= (PLpgSQL_var*) (estate->datums[stmt->var->varno]);
15361537

15371538
/*
1538-
* Get the value of the lower bound into the loop var
1539+
* Get the value of the lower bound
15391540
*/
15401541
value=exec_eval_expr(estate,stmt->lower,&isnull,&valtype);
15411542
value=exec_cast_value(value,valtype,var->datatype->typoid,
@@ -1546,8 +1547,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
15461547
ereport(ERROR,
15471548
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
15481549
errmsg("lower bound of FOR loop cannot be NULL")));
1549-
var->value=value;
1550-
var->isnull= false;
1550+
loop_value=DatumGetInt32(value);
15511551
exec_eval_cleanup(estate);
15521552

15531553
/*
@@ -1562,44 +1562,60 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
15621562
ereport(ERROR,
15631563
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
15641564
errmsg("upper bound of FOR loop cannot be NULL")));
1565+
end_value=DatumGetInt32(value);
15651566
exec_eval_cleanup(estate);
15661567

15671568
/*
1568-
* Get theby value
1569+
* Get thestep value
15691570
*/
1570-
by_value=exec_eval_expr(estate,stmt->by,&isnull,&valtype);
1571-
by_value=exec_cast_value(by_value,valtype,var->datatype->typoid,
1572-
&(var->datatype->typinput),
1573-
var->datatype->typioparam,
1574-
var->datatype->atttypmod,isnull);
1575-
1576-
if (isnull)
1577-
ereport(ERROR,
1578-
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1579-
errmsg("by value of FOR loop cannot be NULL")));
1580-
exec_eval_cleanup(estate);
1571+
if (stmt->step)
1572+
{
1573+
value=exec_eval_expr(estate,stmt->step,&isnull,&valtype);
1574+
value=exec_cast_value(value,valtype,var->datatype->typoid,
1575+
&(var->datatype->typinput),
1576+
var->datatype->typioparam,
1577+
var->datatype->atttypmod,isnull);
1578+
if (isnull)
1579+
ereport(ERROR,
1580+
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
1581+
errmsg("BY value of FOR loop cannot be NULL")));
1582+
step_value=DatumGetInt32(value);
1583+
exec_eval_cleanup(estate);
1584+
if (step_value <=0)
1585+
ereport(ERROR,
1586+
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
1587+
errmsg("BY value of FOR loop must be greater than zero")));
1588+
}
1589+
else
1590+
step_value=1;
15811591

15821592
/*
15831593
* Now do the loop
15841594
*/
15851595
for (;;)
15861596
{
15871597
/*
1588-
* Checkbounds
1598+
* Checkagainst upper bound
15891599
*/
15901600
if (stmt->reverse)
15911601
{
1592-
if ((int4) (var->value)< (int4)value)
1602+
if (loop_value<end_value)
15931603
break;
15941604
}
15951605
else
15961606
{
1597-
if ((int4) (var->value)> (int4)value)
1607+
if (loop_value>end_value)
15981608
break;
15991609
}
16001610

16011611
found= true;/* looped at least once */
16021612

1613+
/*
1614+
* Assign current value to loop var
1615+
*/
1616+
var->value=Int32GetDatum(loop_value);
1617+
var->isnull= false;
1618+
16031619
/*
16041620
* Execute the statements
16051621
*/
@@ -1625,13 +1641,12 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
16251641
* current statement's label, if any: return RC_EXIT so that the
16261642
* EXIT continues to propagate up the stack.
16271643
*/
1628-
16291644
break;
16301645
}
16311646
elseif (rc==PLPGSQL_RC_CONTINUE)
16321647
{
16331648
if (estate->exitlabel==NULL)
1634-
/*anonymous continue, so re-run the current loop */
1649+
/*unlabelled continue, so re-run the current loop */
16351650
rc=PLPGSQL_RC_OK;
16361651
elseif (stmt->label!=NULL&&
16371652
strcmp(stmt->label,estate->exitlabel)==0)
@@ -1652,12 +1667,21 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
16521667
}
16531668

16541669
/*
1655-
* Increase/decrease loop var
1670+
* Increase/decrease loop value, unless it would overflow, in which
1671+
* case exit the loop.
16561672
*/
16571673
if (stmt->reverse)
1658-
var->value-=by_value;
1674+
{
1675+
if ((int32) (loop_value-step_value)>loop_value)
1676+
break;
1677+
loop_value-=step_value;
1678+
}
16591679
else
1660-
var->value+=by_value;
1680+
{
1681+
if ((int32) (loop_value+step_value)<loop_value)
1682+
break;
1683+
loop_value+=step_value;
1684+
}
16611685
}
16621686

16631687
/*

‎src/pl/plpgsql/src/pl_funcs.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.59 2007/04/29 01:21:09 neilc Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_funcs.c,v 1.60 2007/07/15 02:15:04 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -701,8 +701,8 @@ dump_fori(PLpgSQL_stmt_fori *stmt)
701701
dump_expr(stmt->upper);
702702
printf("\n");
703703
dump_ind();
704-
printf("by = ");
705-
dump_expr(stmt->by);
704+
printf("step = ");
705+
dump_expr(stmt->step);
706706
printf("\n");
707707
dump_indent-=2;
708708

‎src/pl/plpgsql/src/plpgsql.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.88 2007/04/29 01:21:09 neilc Exp $
11+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/plpgsql.h,v 1.89 2007/07/15 02:15:04 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -402,7 +402,7 @@ typedef struct
402402
PLpgSQL_var*var;
403403
PLpgSQL_expr*lower;
404404
PLpgSQL_expr*upper;
405-
PLpgSQL_expr*by;
405+
PLpgSQL_expr*step;/* NULL means default (ie, BY 1) */
406406
intreverse;
407407
List*body;/* List of statements */
408408
}PLpgSQL_stmt_fori;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp