Skip to content

Commit 9e3ad1a

Browse files
committed
Use fast path in plpgsql's RETURN/RETURN NEXT in more cases.
exec_stmt_return() and exec_stmt_return_next() have fast-path code for handling a simple variable reference (i.e. "return var") without going through the full expression evaluation machinery. For some reason, pl_gram.y was under the impression that this fast path only applied for record/row variables; but in reality code for handling regular scalar variables has been there all along. Adjusting the logic to allow that code to be used actually results in a net savings of code in pl_gram.y (by eliminating some redundancy), and it buys a measurable though not very impressive amount of speedup. Noted while fooling with my expanded-array patch, wherein this makes a much bigger difference because it enables returning an expanded array variable without an extra flattening step. But AFAICS this is a win regardless, so commit it separately.
1 parent 2c75531 commit 9e3ad1a

File tree

2 files changed

+28
-24
lines changed

2 files changed

+28
-24
lines changed

src/pl/plpgsql/src/pl_exec.c

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2452,8 +2452,9 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
24522452
estate->retisnull = true;
24532453

24542454
/*
2455-
* This special-case path covers record/row variables in fn_retistuple
2456-
* functions, as well as functions with one or more OUT parameters.
2455+
* Special case path when the RETURN expression is a simple variable
2456+
* reference; in particular, this path is always taken in functions with
2457+
* one or more OUT parameters.
24572458
*/
24582459
if (stmt->retvarno >= 0)
24592460
{
@@ -2576,8 +2577,9 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
25762577
natts = tupdesc->natts;
25772578

25782579
/*
2579-
* This special-case path covers record/row variables in fn_retistuple
2580-
* functions, as well as functions with one or more OUT parameters.
2580+
* Special case path when the RETURN NEXT expression is a simple variable
2581+
* reference; in particular, this path is always taken in functions with
2582+
* one or more OUT parameters.
25812583
*/
25822584
if (stmt->retvarno >= 0)
25832585
{

src/pl/plpgsql/src/pl_gram.y

Lines changed: 22 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3036,16 +3036,17 @@ make_return_stmt(int location)
30363036
errmsg("RETURN cannot have a parameter in function returning void"),
30373037
parser_errposition(yylloc)));
30383038
}
3039-
else if (plpgsql_curr_compile->fn_retistuple)
3039+
else
30403040
{
30413041
/*
3042-
* We want to special-case simple row or record references for
3043-
* efficiency. So peek ahead to see if that's what we have.
3042+
* We want to special-case simple variable references for efficiency.
3043+
* So peek ahead to see if that's what we have.
30443044
*/
30453045
int tok = yylex();
30463046

30473047
if (tok == T_DATUM && plpgsql_peek() == ';' &&
3048-
(yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
3048+
(yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
3049+
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
30493050
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC))
30503051
{
30513052
new->retvarno = yylval.wdatum.datum->dno;
@@ -3055,19 +3056,16 @@ make_return_stmt(int location)
30553056
}
30563057
else
30573058
{
3058-
/* Not (just) a row/record name, so treat as expression */
3059+
/*
3060+
* Not (just) a variable name, so treat as expression.
3061+
*
3062+
* Note that a well-formed expression is _required_ here;
3063+
* anything else is a compile-time error.
3064+
*/
30593065
plpgsql_push_back_token(tok);
30603066
new->expr = read_sql_expression(';', ";");
30613067
}
30623068
}
3063-
else
3064-
{
3065-
/*
3066-
* Note that a well-formed expression is _required_ here;
3067-
* anything else is a compile-time error.
3068-
*/
3069-
new->expr = read_sql_expression(';', ";");
3070-
}
30713069

30723070
return (PLpgSQL_stmt *) new;
30733071
}
@@ -3099,16 +3097,17 @@ make_return_next_stmt(int location)
30993097
parser_errposition(yylloc)));
31003098
new->retvarno = plpgsql_curr_compile->out_param_varno;
31013099
}
3102-
else if (plpgsql_curr_compile->fn_retistuple)
3100+
else
31033101
{
31043102
/*
3105-
* We want to special-case simple row or record references for
3106-
* efficiency. So peek ahead to see if that's what we have.
3103+
* We want to special-case simple variable references for efficiency.
3104+
* So peek ahead to see if that's what we have.
31073105
*/
31083106
int tok = yylex();
31093107

31103108
if (tok == T_DATUM && plpgsql_peek() == ';' &&
3111-
(yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
3109+
(yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
3110+
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
31123111
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC))
31133112
{
31143113
new->retvarno = yylval.wdatum.datum->dno;
@@ -3118,13 +3117,16 @@ make_return_next_stmt(int location)
31183117
}
31193118
else
31203119
{
3121-
/* Not (just) a row/record name, so treat as expression */
3120+
/*
3121+
* Not (just) a variable name, so treat as expression.
3122+
*
3123+
* Note that a well-formed expression is _required_ here;
3124+
* anything else is a compile-time error.
3125+
*/
31223126
plpgsql_push_back_token(tok);
31233127
new->expr = read_sql_expression(';', ";");
31243128
}
31253129
}
3126-
else
3127-
new->expr = read_sql_expression(';', ";");
31283130

31293131
return (PLpgSQL_stmt *) new;
31303132
}

0 commit comments

Comments
 (0)