@@ -155,6 +155,80 @@ typedef struct /* cast_hash table entry */
155
155
static MemoryContext shared_cast_context = NULL ;
156
156
static HTAB * shared_cast_hash = NULL ;
157
157
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
+
158
232
/************************************************************
159
233
* Local function forward declarations
160
234
************************************************************/
@@ -1476,7 +1550,9 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
1476
1550
estate -> err_text = NULL ;
1477
1551
1478
1552
/*
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.
1480
1556
*/
1481
1557
switch (rc )
1482
1558
{
@@ -1486,11 +1562,6 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
1486
1562
return rc ;
1487
1563
1488
1564
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
- */
1494
1565
if (estate -> exitlabel == NULL )
1495
1566
return PLPGSQL_RC_EXIT ;
1496
1567
if (block -> label == NULL )
@@ -1948,45 +2019,16 @@ exec_stmt_case(PLpgSQL_execstate *estate, PLpgSQL_stmt_case *stmt)
1948
2019
static int
1949
2020
exec_stmt_loop (PLpgSQL_execstate * estate , PLpgSQL_stmt_loop * stmt )
1950
2021
{
2022
+ int rc = PLPGSQL_RC_OK ;
2023
+
1951
2024
for (;;)
1952
2025
{
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 );
1985
2027
1986
- default :
1987
- elog (ERROR , "unrecognized rc: %d" , rc );
1988
- }
2028
+ LOOP_RC_PROCESSING (stmt -> label , break );
1989
2029
}
2030
+
2031
+ return rc ;
1990
2032
}
1991
2033
1992
2034
@@ -1999,9 +2041,10 @@ exec_stmt_loop(PLpgSQL_execstate *estate, PLpgSQL_stmt_loop *stmt)
1999
2041
static int
2000
2042
exec_stmt_while (PLpgSQL_execstate * estate , PLpgSQL_stmt_while * stmt )
2001
2043
{
2044
+ int rc = PLPGSQL_RC_OK ;
2045
+
2002
2046
for (;;)
2003
2047
{
2004
- int rc ;
2005
2048
bool value ;
2006
2049
bool isnull ;
2007
2050
@@ -2013,43 +2056,10 @@ exec_stmt_while(PLpgSQL_execstate *estate, PLpgSQL_stmt_while *stmt)
2013
2056
2014
2057
rc = exec_stmts (estate , stmt -> body );
2015
2058
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 );
2050
2060
}
2051
2061
2052
- return PLPGSQL_RC_OK ;
2062
+ return rc ;
2053
2063
}
2054
2064
2055
2065
@@ -2163,50 +2173,7 @@ exec_stmt_fori(PLpgSQL_execstate *estate, PLpgSQL_stmt_fori *stmt)
2163
2173
*/
2164
2174
rc = exec_stmts (estate , stmt -> body );
2165
2175
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 );
2210
2177
2211
2178
/*
2212
2179
* 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)
2536
2503
*/
2537
2504
rc = exec_stmts (estate , stmt -> body );
2538
2505
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 );
2584
2507
2585
2508
MemoryContextSwitchTo (stmt_mcontext );
2586
2509
}
@@ -5381,60 +5304,7 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
5381
5304
*/
5382
5305
rc = exec_stmts (estate , stmt -> body );
5383
5306
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 );
5438
5308
}
5439
5309
5440
5310
SPI_freetuptable (tuptab );
0 commit comments