Fix plpgsql so that when a local variable has no initial-value expression,

an error will be thrown correctly if the variable is of a NOT NULL domain.
Report and almost-correct fix from Sergiy Vyshnevetskiy (bug ).
This commit is contained in:
Tom Lane 2007-02-01 19:22:07 +00:00
parent db047e571d
commit 6994d0b891
3 changed files with 52 additions and 1 deletions
src
pl/plpgsql/src
test/regress

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.186 2007/01/30 18:02:22 tgl Exp $ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.187 2007/02/01 19:22:07 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
@ -890,8 +890,27 @@ exec_stmt_block(PLpgSQL_execstate *estate, PLpgSQL_stmt_block *block)
{ {
if (var->default_val == NULL) if (var->default_val == NULL)
{ {
/* Initially it contains a NULL */
var->value = (Datum) 0; var->value = (Datum) 0;
var->isnull = true; var->isnull = true;
/*
* If needed, give the datatype a chance to reject
* NULLs, by assigning a NULL to the variable.
* We claim the value is of type UNKNOWN, not the
* var's datatype, else coercion will be skipped.
* (Do this before the notnull check to be
* consistent with exec_assign_value.)
*/
if (!var->datatype->typinput.fn_strict)
{
bool valIsNull = true;
exec_assign_value(estate,
(PLpgSQL_datum *) var,
(Datum) 0,
UNKNOWNOID,
&valIsNull);
}
if (var->notnull) if (var->notnull)
ereport(ERROR, ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED), (errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),

@ -382,6 +382,22 @@ ERROR: domain pos_int does not allow null values
-- and local variables are enforced correctly. -- and local variables are enforced correctly.
create function doubledecrement(p1 pos_int) returns pos_int as $$ create function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int; declare v pos_int;
begin
return p1;
end$$ language plpgsql;
select doubledecrement(3); -- fail because of implicit null assignment
ERROR: domain pos_int does not allow null values
CONTEXT: PL/pgSQL function "doubledecrement" line 2 during statement block local variable initialization
create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int := 0;
begin
return p1;
end$$ language plpgsql;
select doubledecrement(3); -- fail at initialization assignment
ERROR: value for domain pos_int violates check constraint "pos_int_check"
CONTEXT: PL/pgSQL function "doubledecrement" line 2 during statement block local variable initialization
create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int := 1;
begin begin
v := p1 - 1; v := p1 - 1;
return v - 1; return v - 1;

@ -309,6 +309,22 @@ execute s1(NULL); -- should fail
create function doubledecrement(p1 pos_int) returns pos_int as $$ create function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int; declare v pos_int;
begin
return p1;
end$$ language plpgsql;
select doubledecrement(3); -- fail because of implicit null assignment
create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int := 0;
begin
return p1;
end$$ language plpgsql;
select doubledecrement(3); -- fail at initialization assignment
create or replace function doubledecrement(p1 pos_int) returns pos_int as $$
declare v pos_int := 1;
begin begin
v := p1 - 1; v := p1 - 1;
return v - 1; return v - 1;