@@ -155,6 +155,80 @@ typedef struct /* cast_hash table entry */
155155static MemoryContext shared_cast_context = NULL ;
156156static HTAB * 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+ #define LOOP_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+ else if (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+ else if ((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 return rc ;
14871563
14881564 case PLPGSQL_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 return PLPGSQL_RC_EXIT ;
14961567 if (block -> label == NULL )
@@ -1948,45 +2019,16 @@ exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
19482019static int
19492020exec_stmt_loop (PLpgSQL_execstate * estate , PLpgSQL_stmt_loop * stmt )
19502021{
2022+ int rc = PLPGSQL_RC_OK ;
2023+
19512024 for (;;)
19522025 {
1953- int rc = exec_stmts (estate , stmt -> body );
1954-
1955- switch (rc )
1956- {
1957- case PLPGSQL_RC_OK :
1958- break ;
1959-
1960- case PLPGSQL_RC_EXIT :
1961- if (estate -> exitlabel == NULL )
1962- return PLPGSQL_RC_OK ;
1963- if (stmt -> label == NULL )
1964- return PLPGSQL_RC_EXIT ;
1965- if (strcmp (stmt -> label , estate -> exitlabel ) != 0 )
1966- return PLPGSQL_RC_EXIT ;
1967- estate -> exitlabel = NULL ;
1968- return PLPGSQL_RC_OK ;
1969-
1970- case PLPGSQL_RC_CONTINUE :
1971- if (estate -> exitlabel == NULL )
1972- /* anonymous continue, so re-run the loop */
1973- break ;
1974- else if (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- return PLPGSQL_RC_CONTINUE ;
1981- break ;
1982-
1983- case PLPGSQL_RC_RETURN :
1984- return rc ;
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+ return rc ;
19902032}
19912033
19922034
@@ -1999,9 +2041,10 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
19992041static int
20002042exec_stmt_while (PLpgSQL_execstate * estate , PLpgSQL_stmt_while * stmt )
20012043{
2044+ int rc = PLPGSQL_RC_OK ;
2045+
20022046 for (;;)
20032047 {
2004- int rc ;
20052048 bool value ;
20062049 bool isnull ;
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- case PLPGSQL_RC_OK :
2019- break ;
2020-
2021- case PLPGSQL_RC_EXIT :
2022- if (estate -> exitlabel == NULL )
2023- return PLPGSQL_RC_OK ;
2024- if (stmt -> label == NULL )
2025- return PLPGSQL_RC_EXIT ;
2026- if (strcmp (stmt -> label , estate -> exitlabel ) != 0 )
2027- return PLPGSQL_RC_EXIT ;
2028- estate -> exitlabel = NULL ;
2029- return PLPGSQL_RC_OK ;
2030-
2031- case PLPGSQL_RC_CONTINUE :
2032- if (estate -> exitlabel == NULL )
2033- /* anonymous continue, so re-run loop */
2034- break ;
2035- else if (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- return PLPGSQL_RC_CONTINUE ;
2042- break ;
2043-
2044- case PLPGSQL_RC_RETURN :
2045- return rc ;
2046-
2047- default :
2048- elog (ERROR , "unrecognized rc: %d" , rc );
2049- }
2059+ LOOP_RC_PROCESSING (stmt -> label , break );
20502060 }
20512061
2052- return PLPGSQL_RC_OK ;
2062+ return rc ;
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- else if (rc == PLPGSQL_RC_EXIT )
2169- {
2170- if (estate -> exitlabel == NULL )
2171- /* unlabelled exit, finish the current loop */
2172- rc = PLPGSQL_RC_OK ;
2173- else if (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- else if (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- else if (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- else if (rc == PLPGSQL_RC_EXIT )
2543- {
2544- if (estate -> exitlabel == NULL )
2545- /* unlabelled exit, finish the current loop */
2546- rc = PLPGSQL_RC_OK ;
2547- else if (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- else if (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- else if (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- else if (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- else if (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- else if (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- goto loop_exit ;
5437- }
5307+ LOOP_RC_PROCESSING (stmt -> label , goto loop_exit );
54385308 }
54395309
54405310 SPI_freetuptable (tuptab );
0 commit comments