Re: BUG #2948: default null values for not-null domains - Mailing list pgsql-bugs

From Tom Lane
Subject Re: BUG #2948: default null values for not-null domains
Date
Msg-id 22892.1170358094@sss.pgh.pa.us
Whole thread Raw
In response to Re: BUG #2948: default null values for not-null domains  (Sergiy Vyshnevetskiy <serg@vostok.net>)
Responses Re: BUG #2948: default null values for not-null domains
List pgsql-bugs
Sergiy Vyshnevetskiy <serg@vostok.net> 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;

pgsql-bugs by date:

Previous
From: Sergiy Vyshnevetskiy
Date:
Subject: Re: BUG #2948: default null values for not-null domains
Next
From: Tom Lane
Date:
Subject: Re: BUG #2954: null is not checked against domain constraints in return clause