From 9e3ad1aac52454569393a947c06be0d301749362 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 16 Feb 2015 15:28:40 -0500 Subject: [PATCH] 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. --- src/pl/plpgsql/src/pl_exec.c | 10 +++++---- src/pl/plpgsql/src/pl_gram.y | 42 +++++++++++++++++++----------------- 2 files changed, 28 insertions(+), 24 deletions(-) diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index f5ed02a048..b7e3bc4235 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -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) { diff --git a/src/pl/plpgsql/src/pl_gram.y b/src/pl/plpgsql/src/pl_gram.y index 590aac501b..506a313f70 100644 --- a/src/pl/plpgsql/src/pl_gram.y +++ b/src/pl/plpgsql/src/pl_gram.y @@ -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; } -- 2.39.5