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.
This commit is contained in:
parent
2c75531a6c
commit
9e3ad1aac5
|
@ -2452,8 +2452,9 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
|
|||
estate->retisnull = true;
|
||||
|
||||
/*
|
||||
* This special-case path covers record/row variables in fn_retistuple
|
||||
* functions, as well as functions with one or more OUT parameters.
|
||||
* Special case path when the RETURN expression is a simple variable
|
||||
* reference; in particular, this path is always taken in functions with
|
||||
* one or more OUT parameters.
|
||||
*/
|
||||
if (stmt->retvarno >= 0)
|
||||
{
|
||||
|
@ -2576,8 +2577,9 @@ exec_stmt_return_next(PLpgSQL_execstate *estate,
|
|||
natts = tupdesc->natts;
|
||||
|
||||
/*
|
||||
* This special-case path covers record/row variables in fn_retistuple
|
||||
* functions, as well as functions with one or more OUT parameters.
|
||||
* Special case path when the RETURN NEXT expression is a simple variable
|
||||
* reference; in particular, this path is always taken in functions with
|
||||
* one or more OUT parameters.
|
||||
*/
|
||||
if (stmt->retvarno >= 0)
|
||||
{
|
||||
|
|
|
@ -3036,16 +3036,17 @@ make_return_stmt(int location)
|
|||
errmsg("RETURN cannot have a parameter in function returning void"),
|
||||
parser_errposition(yylloc)));
|
||||
}
|
||||
else if (plpgsql_curr_compile->fn_retistuple)
|
||||
else
|
||||
{
|
||||
/*
|
||||
* We want to special-case simple row or record references for
|
||||
* efficiency. So peek ahead to see if that's what we have.
|
||||
* We want to special-case simple variable references for efficiency.
|
||||
* So peek ahead to see if that's what we have.
|
||||
*/
|
||||
int tok = yylex();
|
||||
|
||||
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))
|
||||
{
|
||||
new->retvarno = yylval.wdatum.datum->dno;
|
||||
|
@ -3055,19 +3056,16 @@ make_return_stmt(int location)
|
|||
}
|
||||
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);
|
||||
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;
|
||||
}
|
||||
|
@ -3099,16 +3097,17 @@ make_return_next_stmt(int location)
|
|||
parser_errposition(yylloc)));
|
||||
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
|
||||
* efficiency. So peek ahead to see if that's what we have.
|
||||
* We want to special-case simple variable references for efficiency.
|
||||
* So peek ahead to see if that's what we have.
|
||||
*/
|
||||
int tok = yylex();
|
||||
|
||||
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))
|
||||
{
|
||||
new->retvarno = yylval.wdatum.datum->dno;
|
||||
|
@ -3118,13 +3117,16 @@ make_return_next_stmt(int location)
|
|||
}
|
||||
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);
|
||||
new->expr = read_sql_expression(';', ";");
|
||||
}
|
||||
}
|
||||
else
|
||||
new->expr = read_sql_expression(';', ";");
|
||||
|
||||
return (PLpgSQL_stmt *) new;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue