Commit 9e3ad1aa authored by Tom Lane's avatar Tom Lane

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.
parent 2c75531a
...@@ -2452,8 +2452,9 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt) ...@@ -2452,8 +2452,9 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
estate->retisnull = true; estate->retisnull = true;
/* /*
* This special-case path covers record/row variables in fn_retistuple * Special case path when the RETURN expression is a simple variable
* functions, as well as functions with one or more OUT parameters. * reference; in particular, this path is always taken in functions with
* one or more OUT parameters.
*/ */
if (stmt->retvarno >= 0) if (stmt->retvarno >= 0)
{ {
...@@ -2576,8 +2577,9 @@ exec_stmt_return_next(PLpgSQL_execstate *estate, ...@@ -2576,8 +2577,9 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
natts = tupdesc->natts; natts = tupdesc->natts;
/* /*
* This special-case path covers record/row variables in fn_retistuple * Special case path when the RETURN NEXT expression is a simple variable
* functions, as well as functions with one or more OUT parameters. * reference; in particular, this path is always taken in functions with
* one or more OUT parameters.
*/ */
if (stmt->retvarno >= 0) if (stmt->retvarno >= 0)
{ {
......
...@@ -3036,16 +3036,17 @@ make_return_stmt(int location) ...@@ -3036,16 +3036,17 @@ make_return_stmt(int location)
errmsg("RETURN cannot have a parameter in function returning void"), errmsg("RETURN cannot have a parameter in function returning void"),
parser_errposition(yylloc))); parser_errposition(yylloc)));
} }
else if (plpgsql_curr_compile->fn_retistuple) else
{ {
/* /*
* We want to special-case simple row or record references for * We want to special-case simple variable references for efficiency.
* efficiency. So peek ahead to see if that's what we have. * So peek ahead to see if that's what we have.
*/ */
int tok = yylex(); int tok = yylex();
if (tok == T_DATUM && plpgsql_peek() == ';' && if (tok == T_DATUM && plpgsql_peek() == ';' &&
(yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)) yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC))
{ {
new->retvarno = yylval.wdatum.datum->dno; new->retvarno = yylval.wdatum.datum->dno;
...@@ -3055,19 +3056,16 @@ make_return_stmt(int location) ...@@ -3055,19 +3056,16 @@ make_return_stmt(int location)
} }
else else
{ {
/* Not (just) a row/record name, so treat as expression */ /*
* Not (just) a variable name, so treat as expression.
*
* Note that a well-formed expression is _required_ here;
* anything else is a compile-time error.
*/
plpgsql_push_back_token(tok); plpgsql_push_back_token(tok);
new->expr = read_sql_expression(';', ";"); new->expr = read_sql_expression(';', ";");
} }
} }
else
{
/*
* Note that a well-formed expression is _required_ here;
* anything else is a compile-time error.
*/
new->expr = read_sql_expression(';', ";");
}
return (PLpgSQL_stmt *) new; return (PLpgSQL_stmt *) new;
} }
...@@ -3099,16 +3097,17 @@ make_return_next_stmt(int location) ...@@ -3099,16 +3097,17 @@ make_return_next_stmt(int location)
parser_errposition(yylloc))); parser_errposition(yylloc)));
new->retvarno = plpgsql_curr_compile->out_param_varno; new->retvarno = plpgsql_curr_compile->out_param_varno;
} }
else if (plpgsql_curr_compile->fn_retistuple) else
{ {
/* /*
* We want to special-case simple row or record references for * We want to special-case simple variable references for efficiency.
* efficiency. So peek ahead to see if that's what we have. * So peek ahead to see if that's what we have.
*/ */
int tok = yylex(); int tok = yylex();
if (tok == T_DATUM && plpgsql_peek() == ';' && if (tok == T_DATUM && plpgsql_peek() == ';' &&
(yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW || (yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_VAR ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_ROW ||
yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC)) yylval.wdatum.datum->dtype == PLPGSQL_DTYPE_REC))
{ {
new->retvarno = yylval.wdatum.datum->dno; new->retvarno = yylval.wdatum.datum->dno;
...@@ -3118,13 +3117,16 @@ make_return_next_stmt(int location) ...@@ -3118,13 +3117,16 @@ make_return_next_stmt(int location)
} }
else else
{ {
/* Not (just) a row/record name, so treat as expression */ /*
* Not (just) a variable name, so treat as expression.
*
* Note that a well-formed expression is _required_ here;
* anything else is a compile-time error.
*/
plpgsql_push_back_token(tok); plpgsql_push_back_token(tok);
new->expr = read_sql_expression(';', ";"); new->expr = read_sql_expression(';', ";");
} }
} }
else
new->expr = read_sql_expression(';', ";");
return (PLpgSQL_stmt *) new; return (PLpgSQL_stmt *) new;
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment