Sergiy Vyshnevetskiy <[EMAIL PROTECTED]> writes:
> If input function IS strict then nulls are ALWAYS accepted.
> If input function IS NOT strict then nulls MIGHT be rejectted.
> And the patch is much more simple now (attached).
> Is that it?
Almost right. exec_assign_value() thinks its isNull argument is the
null flag for the *source* value (not sure why it's pass by reference).
As you set it up, var->isnull would be aliased by *isNull, which might
manage to break things within that function if the code were ever
rearranged.
Also, some comments are usually a good idea (if the purpose were
obvious, it'd have been right the first time, no?), and you always need
to check the regression tests --- it turns out that the wrong behavior
was actually being exposed by the tests.
Patch as-applied is attached.
regards, tom lane
Index: src/pl/plpgsql/src/pl_exec.c
===================================================================
RCS file: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v
retrieving revision 1.186
diff -c -r1.186 pl_exec.c
*** src/pl/plpgsql/src/pl_exec.c 30 Jan 2007 18:02:22 -0000 1.186
--- src/pl/plpgsql/src/pl_exec.c 1 Feb 2007 19:10:51 -0000
***************
*** 890,897 ****
--- 890,916 ----
{
if (var->default_val == NULL)
{
+ /* Initially it
contains a NULL */
var->value = (Datum) 0;
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)
ereport(ERROR,
(errcode(ERRCODE_NULL_VALUE_NOT_ALLOWED),
Index: src/test/regress/expected/domain.out
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/expected/domain.out,v
retrieving revision 1.38
diff -c -r1.38 domain.out
*** src/test/regress/expected/domain.out 6 Oct 2006 17:14:01 -0000
1.38
--- src/test/regress/expected/domain.out 1 Feb 2007 19:10:51 -0000
***************
*** 383,388 ****
--- 383,404 ----
create function doubledecrement(p1 pos_int) returns pos_int as $$
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
v := p1 - 1;
return v - 1;
end$$ language plpgsql;
Index: src/test/regress/sql/domain.sql
===================================================================
RCS file: /cvsroot/pgsql/src/test/regress/sql/domain.sql,v
retrieving revision 1.21
diff -c -r1.21 domain.sql
*** src/test/regress/sql/domain.sql 5 Apr 2006 22:11:58 -0000 1.21
--- src/test/regress/sql/domain.sql 1 Feb 2007 19:10:51 -0000
***************
*** 310,315 ****
--- 310,331 ----
create function doubledecrement(p1 pos_int) returns pos_int as $$
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
v := p1 - 1;
return v - 1;
end$$ language plpgsql;
---------------------------(end of broadcast)---------------------------
TIP 3: Have you checked our extensive FAQ?
http://www.postgresql.org/docs/faq