mirror of
https://github.com/postgres/postgres.git
synced 2025-09-03 15:22:11 +03:00
Allow plpgsql functions to omit RETURN command when the function returns
output parameters or VOID or a set. There seems no particular reason to insist on a RETURN in these cases, since the function return value is determined by other elements anyway. Per recent discussion.
This commit is contained in:
@@ -4,7 +4,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.68 2005/04/05 18:05:46 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/gram.y,v 1.69 2005/04/07 14:53:04 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@@ -1071,7 +1071,7 @@ stmt_return : K_RETURN lno
|
||||
else if (plpgsql_curr_compile->fn_rettype == VOIDOID)
|
||||
{
|
||||
if (yylex() != ';')
|
||||
yyerror("function returning void cannot specify RETURN expression");
|
||||
yyerror("RETURN cannot have a parameter in function returning void");
|
||||
}
|
||||
else if (plpgsql_curr_compile->fn_retistuple)
|
||||
{
|
||||
|
@@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.86 2005/04/05 06:22:16 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_comp.c,v 1.87 2005/04/07 14:53:04 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@@ -271,8 +271,8 @@ do_compile(FunctionCallInfo fcinfo,
|
||||
int parse_rc;
|
||||
Oid rettypeid;
|
||||
int numargs;
|
||||
int num_in_args;
|
||||
int num_out_args;
|
||||
int num_in_args = 0;
|
||||
int num_out_args = 0;
|
||||
Oid *argtypes;
|
||||
char **argnames;
|
||||
char *argmodes;
|
||||
@@ -374,7 +374,6 @@ do_compile(FunctionCallInfo fcinfo,
|
||||
/*
|
||||
* Create the variables for the procedure's parameters.
|
||||
*/
|
||||
num_in_args = num_out_args = 0;
|
||||
for (i = 0; i < numargs; i++)
|
||||
{
|
||||
char buf[32];
|
||||
@@ -641,12 +640,48 @@ do_compile(FunctionCallInfo fcinfo,
|
||||
parse_rc = plpgsql_yyparse();
|
||||
if (parse_rc != 0)
|
||||
elog(ERROR, "plpgsql parser returned %d", parse_rc);
|
||||
function->action = plpgsql_yylval.program;
|
||||
|
||||
plpgsql_scanner_finish();
|
||||
pfree(proc_source);
|
||||
|
||||
/*
|
||||
* If that was successful, complete the function's info.
|
||||
* If it has OUT parameters or returns VOID or returns a set, we allow
|
||||
* control to fall off the end without an explicit RETURN statement.
|
||||
* The easiest way to implement this is to add a RETURN statement to the
|
||||
* end of the statement list during parsing. However, if the outer block
|
||||
* has an EXCEPTION clause, we need to make a new outer block, since the
|
||||
* added RETURN shouldn't act like it is inside the EXCEPTION clause.
|
||||
*/
|
||||
if (num_out_args > 0 || function->fn_rettype == VOIDOID ||
|
||||
function->fn_retset)
|
||||
{
|
||||
if (function->action->exceptions != NIL)
|
||||
{
|
||||
PLpgSQL_stmt_block *new;
|
||||
|
||||
new = palloc0(sizeof(PLpgSQL_stmt_block));
|
||||
new->cmd_type = PLPGSQL_STMT_BLOCK;
|
||||
new->body = list_make1(function->action);
|
||||
|
||||
function->action = new;
|
||||
}
|
||||
if (function->action->body == NIL ||
|
||||
((PLpgSQL_stmt *) llast(function->action->body))->cmd_type != PLPGSQL_STMT_RETURN)
|
||||
{
|
||||
PLpgSQL_stmt_return *new;
|
||||
|
||||
new = palloc0(sizeof(PLpgSQL_stmt_return));
|
||||
new->cmd_type = PLPGSQL_STMT_RETURN;
|
||||
new->expr = NULL;
|
||||
new->retvarno = function->out_param_varno;
|
||||
|
||||
function->action->body = lappend(function->action->body, new);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Complete the function's info
|
||||
*/
|
||||
function->fn_nargs = procStruct->pronargs;
|
||||
for (i = 0; i < function->fn_nargs; i++)
|
||||
@@ -655,7 +690,6 @@ do_compile(FunctionCallInfo fcinfo,
|
||||
function->datums = palloc(sizeof(PLpgSQL_datum *) * plpgsql_nDatums);
|
||||
for (i = 0; i < plpgsql_nDatums; i++)
|
||||
function->datums[i] = plpgsql_Datums[i];
|
||||
function->action = plpgsql_yylval.program;
|
||||
|
||||
/* Debug dump for completed functions */
|
||||
if (plpgsql_DumpExecTree)
|
||||
|
@@ -3,7 +3,7 @@
|
||||
* procedural language
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.134 2005/04/05 06:22:16 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.135 2005/04/07 14:53:04 tgl Exp $
|
||||
*
|
||||
* This software is copyrighted by Jan Wieck - Hamburg.
|
||||
*
|
||||
@@ -1691,12 +1691,18 @@ exec_stmt_return(PLpgSQL_execstate *estate, PLpgSQL_stmt_return *stmt)
|
||||
&(estate->retisnull),
|
||||
&(estate->rettype));
|
||||
}
|
||||
|
||||
return PLPGSQL_RC_RETURN;
|
||||
}
|
||||
|
||||
/*
|
||||
* Special hack for function returning VOID: instead of NULL, return a
|
||||
* non-null VOID value. This is of dubious importance but is kept for
|
||||
* backwards compatibility. Note that the only other way to get here
|
||||
* is to have written "RETURN NULL" in a function returning tuple.
|
||||
*/
|
||||
if (estate->fn_rettype == VOIDOID)
|
||||
{
|
||||
/* Special hack for function returning VOID */
|
||||
Assert(stmt->retvarno < 0 && stmt->expr == NULL);
|
||||
estate->retval = (Datum) 0;
|
||||
estate->retisnull = false;
|
||||
estate->rettype = VOIDOID;
|
||||
|
@@ -1739,7 +1739,8 @@ SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
|
||||
(1 row)
|
||||
|
||||
--
|
||||
-- Test handling of OUT parameters, including polymorphic cases
|
||||
-- Test handling of OUT parameters, including polymorphic cases.
|
||||
-- Note that RETURN is optional with OUT params; we try both ways.
|
||||
--
|
||||
-- wrong way to do it:
|
||||
create function f1(in i int, out j int) returns int as $$
|
||||
@@ -1769,7 +1770,6 @@ select * from f1(42);
|
||||
create or replace function f1(inout i int) as $$
|
||||
begin
|
||||
i := i+1;
|
||||
return;
|
||||
end$$ language plpgsql;
|
||||
select f1(42);
|
||||
f1
|
||||
@@ -1805,7 +1805,6 @@ begin
|
||||
j := i;
|
||||
j := j+1;
|
||||
k := 'foo';
|
||||
return;
|
||||
end$$ language plpgsql;
|
||||
select f1(42);
|
||||
f1
|
||||
@@ -1828,7 +1827,6 @@ begin
|
||||
j := j+1;
|
||||
k := 'foot';
|
||||
return next;
|
||||
return;
|
||||
end$$ language plpgsql;
|
||||
select * from f1(42);
|
||||
j | k
|
||||
@@ -2358,6 +2356,27 @@ create function void_return_expr() returns void as $$
|
||||
begin
|
||||
return 5;
|
||||
end;$$ language plpgsql;
|
||||
ERROR: function returning void cannot specify RETURN expression at or near "5" at character 72
|
||||
ERROR: RETURN cannot have a parameter in function returning void at or near "5" at character 72
|
||||
LINE 3: return 5;
|
||||
^
|
||||
-- VOID functions are allowed to omit RETURN
|
||||
create function void_return_expr() returns void as $$
|
||||
begin
|
||||
perform 2+2;
|
||||
end;$$ language plpgsql;
|
||||
select void_return_expr();
|
||||
void_return_expr
|
||||
------------------
|
||||
|
||||
(1 row)
|
||||
|
||||
-- but ordinary functions are not
|
||||
create function missing_return_expr() returns int as $$
|
||||
begin
|
||||
perform 2+2;
|
||||
end;$$ language plpgsql;
|
||||
select missing_return_expr();
|
||||
ERROR: control reached end of function without RETURN
|
||||
CONTEXT: PL/pgSQL function "missing_return_expr"
|
||||
drop function void_return_expr();
|
||||
drop function missing_return_expr();
|
||||
|
@@ -1561,7 +1561,8 @@ SELECT * FROM test_ret_rec_dyn(1500) AS (a int, b int, c int);
|
||||
SELECT * FROM test_ret_rec_dyn(5) AS (a int, b numeric, c text);
|
||||
|
||||
--
|
||||
-- Test handling of OUT parameters, including polymorphic cases
|
||||
-- Test handling of OUT parameters, including polymorphic cases.
|
||||
-- Note that RETURN is optional with OUT params; we try both ways.
|
||||
--
|
||||
|
||||
-- wrong way to do it:
|
||||
@@ -1582,7 +1583,6 @@ select * from f1(42);
|
||||
create or replace function f1(inout i int) as $$
|
||||
begin
|
||||
i := i+1;
|
||||
return;
|
||||
end$$ language plpgsql;
|
||||
|
||||
select f1(42);
|
||||
@@ -1608,7 +1608,6 @@ begin
|
||||
j := i;
|
||||
j := j+1;
|
||||
k := 'foo';
|
||||
return;
|
||||
end$$ language plpgsql;
|
||||
|
||||
select f1(42);
|
||||
@@ -1624,7 +1623,6 @@ begin
|
||||
j := j+1;
|
||||
k := 'foot';
|
||||
return next;
|
||||
return;
|
||||
end$$ language plpgsql;
|
||||
|
||||
select * from f1(42);
|
||||
@@ -2001,3 +1999,22 @@ create function void_return_expr() returns void as $$
|
||||
begin
|
||||
return 5;
|
||||
end;$$ language plpgsql;
|
||||
|
||||
-- VOID functions are allowed to omit RETURN
|
||||
create function void_return_expr() returns void as $$
|
||||
begin
|
||||
perform 2+2;
|
||||
end;$$ language plpgsql;
|
||||
|
||||
select void_return_expr();
|
||||
|
||||
-- but ordinary functions are not
|
||||
create function missing_return_expr() returns int as $$
|
||||
begin
|
||||
perform 2+2;
|
||||
end;$$ language plpgsql;
|
||||
|
||||
select missing_return_expr();
|
||||
|
||||
drop function void_return_expr();
|
||||
drop function missing_return_expr();
|
||||
|
Reference in New Issue
Block a user