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: