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

Commit3e724aa

Browse files
committed
Merge coding of return/exit/continue cases in plpgsql's loop statements.
plpgsql's five different loop control statements contained three distinctimplementations of the same (or what ought to be the same, at least)logic for handling return/exit/continue result codes from their childstatements. At best, that's trouble waiting to happen, and there seemsno very good reason for the coding to be so different. Refactor so thatall the common logic is expressed in a single macro.Discussion:https://postgr.es/m/26314.1514670401@sss.pgh.pa.us
1 parentdd2243f commit3e724aa

File tree

1 file changed

+90
-220
lines changed

1 file changed

+90
-220
lines changed

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

Lines changed: 90 additions & 220 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,80 @@ typedef struct/* cast_hash table entry */
155155
staticMemoryContextshared_cast_context=NULL;
156156
staticHTAB*shared_cast_hash=NULL;
157157

158+
/*
159+
* LOOP_RC_PROCESSING encapsulates common logic for looping statements to
160+
* handle return/exit/continue result codes from the loop body statement(s).
161+
* It's meant to be used like this:
162+
*
163+
*int rc = PLPGSQL_RC_OK;
164+
*for (...)
165+
*{
166+
*...
167+
*rc = exec_stmts(estate, stmt->body);
168+
*LOOP_RC_PROCESSING(stmt->label, break);
169+
*...
170+
*}
171+
*return rc;
172+
*
173+
* If execution of the loop should terminate, LOOP_RC_PROCESSING will execute
174+
* "exit_action" (typically a "break" or "goto"), after updating "rc" to the
175+
* value the current statement should return. If execution should continue,
176+
* LOOP_RC_PROCESSING will do nothing except reset "rc" to PLPGSQL_RC_OK.
177+
*
178+
* estate and rc are implicit arguments to the macro.
179+
* estate->exitlabel is examined and possibly updated.
180+
*/
181+
#defineLOOP_RC_PROCESSING(looplabel,exit_action) \
182+
if (rc == PLPGSQL_RC_RETURN) \
183+
{ \
184+
/* RETURN, so propagate RC_RETURN out */ \
185+
exit_action; \
186+
} \
187+
else if (rc == PLPGSQL_RC_EXIT) \
188+
{ \
189+
if (estate->exitlabel == NULL) \
190+
{ \
191+
/* unlabelled EXIT terminates this loop */ \
192+
rc = PLPGSQL_RC_OK; \
193+
exit_action; \
194+
} \
195+
else if ((looplabel) != NULL && \
196+
strcmp(looplabel, estate->exitlabel) == 0) \
197+
{ \
198+
/* labelled EXIT matching this loop, so terminate loop */ \
199+
estate->exitlabel=NULL; \
200+
rc=PLPGSQL_RC_OK; \
201+
exit_action; \
202+
} \
203+
else \
204+
{ \
205+
/* non-matching labelled EXIT, propagate RC_EXIT out */ \
206+
exit_action; \
207+
} \
208+
} \
209+
elseif (rc==PLPGSQL_RC_CONTINUE) \
210+
{ \
211+
if (estate->exitlabel==NULL) \
212+
{ \
213+
/* unlabelled CONTINUE matches this loop, so continue in loop */ \
214+
rc=PLPGSQL_RC_OK; \
215+
} \
216+
elseif ((looplabel)!=NULL&& \
217+
strcmp(looplabel,estate->exitlabel)==0) \
218+
{ \
219+
/* labelled CONTINUE matching this loop, so continue in loop */ \
220+
estate->exitlabel=NULL; \
221+
rc=PLPGSQL_RC_OK; \
222+
} \
223+
else \
224+
{ \
225+
/* non-matching labelled CONTINUE, propagate RC_CONTINUE out */ \
226+
exit_action; \
227+
} \
228+
} \
229+
else \
230+
Assert(rc==PLPGSQL_RC_OK)
231+
158232
/************************************************************
159233
* Local function forward declarations
160234
************************************************************/
@@ -1476,7 +1550,9 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
14761550
estate->err_text=NULL;
14771551

14781552
/*
1479-
* Handle the return code.
1553+
* Handle the return code. This is intentionally different from
1554+
* LOOP_RC_PROCESSING(): CONTINUE never matches a block, and EXIT matches
1555+
* a block only if there is a label match.
14801556
*/
14811557
switch (rc)
14821558
{
@@ -1486,11 +1562,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
14861562
returnrc;
14871563

14881564
casePLPGSQL_RC_EXIT:
1489-
1490-
/*
1491-
* This is intentionally different from the handling of RC_EXIT
1492-
* for loops: to match a block, we require a match by label.
1493-
*/
14941565
if (estate->exitlabel==NULL)
14951566
returnPLPGSQL_RC_EXIT;
14961567
if (block->label==NULL)
@@ -1948,45 +2019,16 @@ exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
19482019
staticint
19492020
exec_stmt_loop(PLpgSQL_execstate*estate,PLpgSQL_stmt_loop*stmt)
19502021
{
2022+
intrc=PLPGSQL_RC_OK;
2023+
19512024
for (;;)
19522025
{
1953-
intrc=exec_stmts(estate,stmt->body);
1954-
1955-
switch (rc)
1956-
{
1957-
casePLPGSQL_RC_OK:
1958-
break;
1959-
1960-
casePLPGSQL_RC_EXIT:
1961-
if (estate->exitlabel==NULL)
1962-
returnPLPGSQL_RC_OK;
1963-
if (stmt->label==NULL)
1964-
returnPLPGSQL_RC_EXIT;
1965-
if (strcmp(stmt->label,estate->exitlabel)!=0)
1966-
returnPLPGSQL_RC_EXIT;
1967-
estate->exitlabel=NULL;
1968-
returnPLPGSQL_RC_OK;
1969-
1970-
casePLPGSQL_RC_CONTINUE:
1971-
if (estate->exitlabel==NULL)
1972-
/* anonymous continue, so re-run the loop */
1973-
break;
1974-
elseif (stmt->label!=NULL&&
1975-
strcmp(stmt->label,estate->exitlabel)==0)
1976-
/* label matches named continue, so re-run loop */
1977-
estate->exitlabel=NULL;
1978-
else
1979-
/* label doesn't match named continue, so propagate upward */
1980-
returnPLPGSQL_RC_CONTINUE;
1981-
break;
1982-
1983-
casePLPGSQL_RC_RETURN:
1984-
returnrc;
2026+
rc=exec_stmts(estate,stmt->body);
19852027

1986-
default:
1987-
elog(ERROR,"unrecognized rc: %d",rc);
1988-
}
2028+
LOOP_RC_PROCESSING(stmt->label,break);
19892029
}
2030+
2031+
returnrc;
19902032
}
19912033

19922034

@@ -1999,9 +2041,10 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
19992041
staticint
20002042
exec_stmt_while(PLpgSQL_execstate*estate,PLpgSQL_stmt_while*stmt)
20012043
{
2044+
intrc=PLPGSQL_RC_OK;
2045+
20022046
for (;;)
20032047
{
2004-
intrc;
20052048
boolvalue;
20062049
boolisnull;
20072050

@@ -2013,43 +2056,10 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
20132056

20142057
rc=exec_stmts(estate,stmt->body);
20152058

2016-
switch (rc)
2017-
{
2018-
casePLPGSQL_RC_OK:
2019-
break;
2020-
2021-
casePLPGSQL_RC_EXIT:
2022-
if (estate->exitlabel==NULL)
2023-
returnPLPGSQL_RC_OK;
2024-
if (stmt->label==NULL)
2025-
returnPLPGSQL_RC_EXIT;
2026-
if (strcmp(stmt->label,estate->exitlabel)!=0)
2027-
returnPLPGSQL_RC_EXIT;
2028-
estate->exitlabel=NULL;
2029-
returnPLPGSQL_RC_OK;
2030-
2031-
casePLPGSQL_RC_CONTINUE:
2032-
if (estate->exitlabel==NULL)
2033-
/* anonymous continue, so re-run loop */
2034-
break;
2035-
elseif (stmt->label!=NULL&&
2036-
strcmp(stmt->label,estate->exitlabel)==0)
2037-
/* label matches named continue, so re-run loop */
2038-
estate->exitlabel=NULL;
2039-
else
2040-
/* label doesn't match named continue, propagate upward */
2041-
returnPLPGSQL_RC_CONTINUE;
2042-
break;
2043-
2044-
casePLPGSQL_RC_RETURN:
2045-
returnrc;
2046-
2047-
default:
2048-
elog(ERROR,"unrecognized rc: %d",rc);
2049-
}
2059+
LOOP_RC_PROCESSING(stmt->label,break);
20502060
}
20512061

2052-
returnPLPGSQL_RC_OK;
2062+
returnrc;
20532063
}
20542064

20552065

@@ -2163,50 +2173,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
21632173
*/
21642174
rc=exec_stmts(estate,stmt->body);
21652175

2166-
if (rc==PLPGSQL_RC_RETURN)
2167-
break;/* break out of the loop */
2168-
elseif (rc==PLPGSQL_RC_EXIT)
2169-
{
2170-
if (estate->exitlabel==NULL)
2171-
/* unlabelled exit, finish the current loop */
2172-
rc=PLPGSQL_RC_OK;
2173-
elseif (stmt->label!=NULL&&
2174-
strcmp(stmt->label,estate->exitlabel)==0)
2175-
{
2176-
/* labelled exit, matches the current stmt's label */
2177-
estate->exitlabel=NULL;
2178-
rc=PLPGSQL_RC_OK;
2179-
}
2180-
2181-
/*
2182-
* otherwise, this is a labelled exit that does not match the
2183-
* current statement's label, if any: return RC_EXIT so that the
2184-
* EXIT continues to propagate up the stack.
2185-
*/
2186-
break;
2187-
}
2188-
elseif (rc==PLPGSQL_RC_CONTINUE)
2189-
{
2190-
if (estate->exitlabel==NULL)
2191-
/* unlabelled continue, so re-run the current loop */
2192-
rc=PLPGSQL_RC_OK;
2193-
elseif (stmt->label!=NULL&&
2194-
strcmp(stmt->label,estate->exitlabel)==0)
2195-
{
2196-
/* label matches named continue, so re-run loop */
2197-
estate->exitlabel=NULL;
2198-
rc=PLPGSQL_RC_OK;
2199-
}
2200-
else
2201-
{
2202-
/*
2203-
* otherwise, this is a named continue that does not match the
2204-
* current statement's label, if any: return RC_CONTINUE so
2205-
* that the CONTINUE will propagate up the stack.
2206-
*/
2207-
break;
2208-
}
2209-
}
2176+
LOOP_RC_PROCESSING(stmt->label,break);
22102177

22112178
/*
22122179
* Increase/decrease loop value, unless it would overflow, in which
@@ -2536,51 +2503,7 @@ exec_stmt_foreach_a(PLpgSQL_execstate *estate, PLpgSQL_stmt_foreach_a *stmt)
25362503
*/
25372504
rc=exec_stmts(estate,stmt->body);
25382505

2539-
/* Handle the return code */
2540-
if (rc==PLPGSQL_RC_RETURN)
2541-
break;/* break out of the loop */
2542-
elseif (rc==PLPGSQL_RC_EXIT)
2543-
{
2544-
if (estate->exitlabel==NULL)
2545-
/* unlabelled exit, finish the current loop */
2546-
rc=PLPGSQL_RC_OK;
2547-
elseif (stmt->label!=NULL&&
2548-
strcmp(stmt->label,estate->exitlabel)==0)
2549-
{
2550-
/* labelled exit, matches the current stmt's label */
2551-
estate->exitlabel=NULL;
2552-
rc=PLPGSQL_RC_OK;
2553-
}
2554-
2555-
/*
2556-
* otherwise, this is a labelled exit that does not match the
2557-
* current statement's label, if any: return RC_EXIT so that the
2558-
* EXIT continues to propagate up the stack.
2559-
*/
2560-
break;
2561-
}
2562-
elseif (rc==PLPGSQL_RC_CONTINUE)
2563-
{
2564-
if (estate->exitlabel==NULL)
2565-
/* unlabelled continue, so re-run the current loop */
2566-
rc=PLPGSQL_RC_OK;
2567-
elseif (stmt->label!=NULL&&
2568-
strcmp(stmt->label,estate->exitlabel)==0)
2569-
{
2570-
/* label matches named continue, so re-run loop */
2571-
estate->exitlabel=NULL;
2572-
rc=PLPGSQL_RC_OK;
2573-
}
2574-
else
2575-
{
2576-
/*
2577-
* otherwise, this is a named continue that does not match the
2578-
* current statement's label, if any: return RC_CONTINUE so
2579-
* that the CONTINUE will propagate up the stack.
2580-
*/
2581-
break;
2582-
}
2583-
}
2506+
LOOP_RC_PROCESSING(stmt->label,break);
25842507

25852508
MemoryContextSwitchTo(stmt_mcontext);
25862509
}
@@ -5381,60 +5304,7 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
53815304
*/
53825305
rc=exec_stmts(estate,stmt->body);
53835306

5384-
if (rc!=PLPGSQL_RC_OK)
5385-
{
5386-
if (rc==PLPGSQL_RC_EXIT)
5387-
{
5388-
if (estate->exitlabel==NULL)
5389-
{
5390-
/* unlabelled exit, so exit the current loop */
5391-
rc=PLPGSQL_RC_OK;
5392-
}
5393-
elseif (stmt->label!=NULL&&
5394-
strcmp(stmt->label,estate->exitlabel)==0)
5395-
{
5396-
/* label matches this loop, so exit loop */
5397-
estate->exitlabel=NULL;
5398-
rc=PLPGSQL_RC_OK;
5399-
}
5400-
5401-
/*
5402-
* otherwise, we processed a labelled exit that does not
5403-
* match the current statement's label, if any; return
5404-
* RC_EXIT so that the EXIT continues to recurse upward.
5405-
*/
5406-
}
5407-
elseif (rc==PLPGSQL_RC_CONTINUE)
5408-
{
5409-
if (estate->exitlabel==NULL)
5410-
{
5411-
/* unlabelled continue, so re-run the current loop */
5412-
rc=PLPGSQL_RC_OK;
5413-
continue;
5414-
}
5415-
elseif (stmt->label!=NULL&&
5416-
strcmp(stmt->label,estate->exitlabel)==0)
5417-
{
5418-
/* label matches this loop, so re-run loop */
5419-
estate->exitlabel=NULL;
5420-
rc=PLPGSQL_RC_OK;
5421-
continue;
5422-
}
5423-
5424-
/*
5425-
* otherwise, we process a labelled continue that does not
5426-
* match the current statement's label, if any; return
5427-
* RC_CONTINUE so that the CONTINUE will propagate up the
5428-
* stack.
5429-
*/
5430-
}
5431-
5432-
/*
5433-
* We're aborting the loop. Need a goto to get out of two
5434-
* levels of loop...
5435-
*/
5436-
gotoloop_exit;
5437-
}
5307+
LOOP_RC_PROCESSING(stmt->label,gotoloop_exit);
54385308
}
54395309

54405310
SPI_freetuptable(tuptab);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp