Your problem is that when you add a new column to the_person
, its child, the_person_two
will have this field appended at the end of columns list (4th position), so after has_default
column. See:
db=> \d temp_person
Column | Type | Modifiers
-----------+-------------------+-----------------------------------------------------------------
person_id | integer | not null default nextval('temp_person_person_id_seq'::regclass)
name | character varying |
foo | text |
db=> \d temp_person_two
Column | Type | Modifiers
-------------+----------------------+-----------------------------------------------------------------
person_id | integer | not null default nextval('temp_person_person_id_seq'::regclass)
name | character varying |
has_default | character varying(4) | not null default 'en'::character varying
foo | text |
So, when you execute this:
INSERT INTO temp_person_two VALUES ( NEW.* );
PostgreSQL will actually understand that you want to insert on the first three columns of temp_person_two
(as NEW.*
will expand to three values), generating something similar to this:
INSERT INTO temp_person_two(person_id,name,has_default)
VALUES ( NEW.person_id, NEW.name, NEW.foo );
So, temp_person_two.has_default
will get the value of NEW.foo
, which is NULL
in your case.
The solution is to simply expand the column names:
INSERT INTO temp_person_two(person_id,name,foo)
VALUES ( NEW.person_id, NEW.name, NEW.foo );
or, you could also use this:
INSERT INTO temp_person_two(person_id,name,foo)
VALUES ( NEW.* );
But this is weak, as any changes on column positions may break your statements, so I'd recommend the first one.
EDIT:
So the conclusion and the lesson learned here is:
Always explicitly type the names of the columns and the values when issuing an INSERT command, in fact, when issuing any SQL command at all... =D
This will save you a lot of time solving problems like that in future.
Best Answer
Use the “is contained in” operator in your check constraint: