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

Commit051d1ba

Browse files
committed
Avoid recursion while processing ELSIF lists in plpgsql.
The original implementation of ELSIF in plpgsql converted the constructinto nested simple IF statements. This was prone to stack overflow withlong ELSIF lists, in two different ways. First, it's difficult to generatethe parsetree without using right-recursion in the bison grammar, andthat's prone to parser stack overflow since nothing can be reduced untilthe whole list has been read. Second, we'd recurse during execution, thuscreating an unnecessary risk of execution-time stack overflow. Rewriteso that the ELSIF list is represented as a flat list, scanned via iterationnot recursion, and generated through left-recursion in the grammar.Per a gripe from Håvard Kongsgård.
1 parent756a4ed commit051d1ba

File tree

4 files changed

+66
-50
lines changed

4 files changed

+66
-50
lines changed

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

Lines changed: 19 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ staticList*read_raise_options(void);
186186

187187
%type<str>any_identifieropt_block_labelopt_label
188188

189-
%type<list>proc_sectproc_stmtsstmt_else
189+
%type<list>proc_sectproc_stmtsstmt_elsifsstmt_else
190190
%type<loop_body>loop_body
191191
%type<stmt>proc_stmtpl_block
192192
%type<stmt>stmt_assignstmt_ifstmt_loopstmt_whilestmt_exit
@@ -1007,55 +1007,43 @@ assign_var: T_DATUM
10071007
}
10081008
;
10091009

1010-
stmt_if: K_IF expr_until_then proc_sect stmt_else K_END K_IF';'
1010+
stmt_if: K_IF expr_until_then proc_sectstmt_elsifsstmt_else K_END K_IF';'
10111011
{
10121012
PLpgSQL_stmt_if *new;
10131013

10141014
new =palloc0(sizeof(PLpgSQL_stmt_if));
10151015
new->cmd_type= PLPGSQL_STMT_IF;
10161016
new->lineno=plpgsql_location_to_lineno(@1);
10171017
new->cond= $2;
1018-
new->true_body= $3;
1019-
new->false_body = $4;
1018+
new->then_body= $3;
1019+
new->elsif_list = $4;
1020+
new->else_body = $5;
10201021

10211022
$$ = (PLpgSQL_stmt *)new;
10221023
}
10231024
;
10241025

1025-
stmt_else:
1026+
stmt_elsifs:
10261027
{
10271028
$$ = NIL;
10281029
}
1029-
| K_ELSIF expr_until_then proc_sect stmt_else
1030-
{
1031-
/*----------
1032-
* Translate the structure: into:
1033-
*
1034-
* IF c1 THEN IF c1 THEN
1035-
* ... ...
1036-
* ELSIF c2 THEN ELSE
1037-
* IF c2 THEN
1038-
* ... ...
1039-
* ELSE ELSE
1040-
* ... ...
1041-
* END IF END IF
1042-
* END IF
1043-
*----------
1044-
*/
1045-
PLpgSQL_stmt_if *new_if;
1030+
| stmt_elsifs K_ELSIF expr_until_then proc_sect
1031+
{
1032+
PLpgSQL_if_elsif *new;
10461033

1047-
/* first create a new if-statement*/
1048-
new_if =palloc0(sizeof(PLpgSQL_stmt_if));
1049-
new_if->cmd_type= PLPGSQL_STMT_IF;
1050-
new_if->lineno=plpgsql_location_to_lineno(@1);
1051-
new_if->cond= $2;
1052-
new_if->true_body= $3;
1053-
new_if->false_body= $4;
1034+
new =palloc0(sizeof(PLpgSQL_if_elsif));
1035+
new->lineno =plpgsql_location_to_lineno(@2);
1036+
new->cond = $3;
1037+
new->stmts = $4;
10541038

1055-
/* wrap the if-statement in a "container" list*/
1056-
$$ =list_make1(new_if);
1039+
$$ =lappend($1,new);
10571040
}
1041+
;
10581042

1043+
stmt_else:
1044+
{
1045+
$$ = NIL;
1046+
}
10591047
| K_ELSE proc_sect
10601048
{
10611049
$$ = $2;

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

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1510,22 +1510,24 @@ exec_stmt_if(PLpgSQL_execstate *estate, PLpgSQL_stmt_if *stmt)
15101510
{
15111511
boolvalue;
15121512
boolisnull;
1513+
ListCell*lc;
15131514

15141515
value=exec_eval_boolean(estate,stmt->cond,&isnull);
15151516
exec_eval_cleanup(estate);
1516-
15171517
if (!isnull&&value)
1518+
returnexec_stmts(estate,stmt->then_body);
1519+
1520+
foreach(lc,stmt->elsif_list)
15181521
{
1519-
if (stmt->true_body!=NIL)
1520-
returnexec_stmts(estate,stmt->true_body);
1521-
}
1522-
else
1523-
{
1524-
if (stmt->false_body!=NIL)
1525-
returnexec_stmts(estate,stmt->false_body);
1522+
PLpgSQL_if_elsif*elif= (PLpgSQL_if_elsif*)lfirst(lc);
1523+
1524+
value=exec_eval_boolean(estate,elif->cond,&isnull);
1525+
exec_eval_cleanup(estate);
1526+
if (!isnull&&value)
1527+
returnexec_stmts(estate,elif->stmts);
15261528
}
15271529

1528-
returnPLPGSQL_RC_OK;
1530+
returnexec_stmts(estate,stmt->else_body);
15291531
}
15301532

15311533

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

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -446,9 +446,18 @@ free_assign(PLpgSQL_stmt_assign *stmt)
446446
staticvoid
447447
free_if(PLpgSQL_stmt_if*stmt)
448448
{
449+
ListCell*l;
450+
449451
free_expr(stmt->cond);
450-
free_stmts(stmt->true_body);
451-
free_stmts(stmt->false_body);
452+
free_stmts(stmt->then_body);
453+
foreach(l,stmt->elsif_list)
454+
{
455+
PLpgSQL_if_elsif*elif= (PLpgSQL_if_elsif*)lfirst(l);
456+
457+
free_expr(elif->cond);
458+
free_stmts(elif->stmts);
459+
}
460+
free_stmts(stmt->else_body);
452461
}
453462

454463
staticvoid
@@ -877,20 +886,29 @@ dump_assign(PLpgSQL_stmt_assign *stmt)
877886
staticvoid
878887
dump_if(PLpgSQL_stmt_if*stmt)
879888
{
889+
ListCell*l;
890+
880891
dump_ind();
881892
printf("IF ");
882893
dump_expr(stmt->cond);
883894
printf(" THEN\n");
895+
dump_stmts(stmt->then_body);
896+
foreach(l,stmt->elsif_list)
897+
{
898+
PLpgSQL_if_elsif*elif= (PLpgSQL_if_elsif*)lfirst(l);
884899

885-
dump_stmts(stmt->true_body);
886-
887-
if (stmt->false_body!=NIL)
900+
dump_ind();
901+
printf(" ELSIF ");
902+
dump_expr(elif->cond);
903+
printf(" THEN\n");
904+
dump_stmts(elif->stmts);
905+
}
906+
if (stmt->else_body!=NIL)
888907
{
889908
dump_ind();
890909
printf(" ELSE\n");
891-
dump_stmts(stmt->false_body);
910+
dump_stmts(stmt->else_body);
892911
}
893-
894912
dump_ind();
895913
printf(" ENDIF\n");
896914
}

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

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -396,11 +396,19 @@ typedef struct
396396
{/* IF statement*/
397397
intcmd_type;
398398
intlineno;
399-
PLpgSQL_expr*cond;
400-
List*true_body;/* List of statements */
401-
List*false_body;/* List of statements */
399+
PLpgSQL_expr*cond;/* boolean expression for THEN */
400+
List*then_body;/* List of statements */
401+
List*elsif_list;/* List of PLpgSQL_if_elsif structs */
402+
List*else_body;/* List of statements */
402403
}PLpgSQL_stmt_if;
403404

405+
typedefstruct/* one ELSIF arm of IF statement */
406+
{
407+
intlineno;
408+
PLpgSQL_expr*cond;/* boolean expression for this case */
409+
List*stmts;/* List of statements */
410+
}PLpgSQL_if_elsif;
411+
404412

405413
typedefstruct/* CASE statement */
406414
{

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp