mirror of
https://github.com/postgres/postgres.git
synced 2025-09-02 04:21:28 +03:00
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:
@@ -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,
|
|||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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)
|
|||||||
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)
|
|||||||
}
|
}
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user