Thread: BUG #15212: Default values in partition tables don't work as expectedand allow NOT NULL violation
BUG #15212: Default values in partition tables don't work as expectedand allow NOT NULL violation
From
PG Bug reporting form
Date:
The following bug has been logged on the website: Bug reference: 15212 Logged by: Jürgen Strobel Email address: juergen+postgresql@strobel.info PostgreSQL version: 10.4 Operating system: Debian Description: I found unexpected behavior when playing around with declarative partitioning. First, any way to define defaults on (child) partition tables is silently ignored when inserting into the master table, but not when inserting into the child table. The easiest way to reproduce this is: jue=> create table ptest (a int, b int) partition by list (a); CREATE TABLE jue=> create table ptest1 partition of ptest (b default 7) for values in (1); CREATE TABLE jue=> insert into ptest (a) values (1); INSERT 0 1 jue=> table ptest; a | b ---+--- 1 | (1 row) jue=> insert into ptest1 (a) values (1); INSERT 0 1 jue=> table ptest; a | b ---+--- 1 | 1 | 7 (2 rows) Second, this is a way to violate a NOT NULL constraint, presumably because a default value should be applied later but isn't: jue=> create table ptest (a int, b int not null) partition by list (a); CREATE TABLE jue=> create table ptest1 partition of ptest (b default 7) for values in (1); CREATE TABLE jue=> insert into ptest (a) values (1); INSERT 0 1 jue=> select * from ptest where b is null; a | b ---+--- 1 | (1 row) The same happens for defaults using nextval(sequence), either if specified directly or as SERIAL columns with ALTER TABLE ... ATTACH PARTITION. My current workaround is to use a before-row trigger to apply the default value.
Re: BUG #15212: Default values in partition tables don't work asexpected and allow NOT NULL violation
From
Amit Langote
Date:
Hello. On 2018/05/28 9:30, PG Bug reporting form wrote: > The following bug has been logged on the website: > > Bug reference: 15212 > Logged by: Jürgen Strobel > Email address: juergen+postgresql@strobel.info > PostgreSQL version: 10.4 > Operating system: Debian > Description: > > I found unexpected behavior when playing around with declarative > partitioning. Thank you for reporting this and sorry it took a while to reply here. > First, any way to define defaults on (child) partition tables is silently > ignored when inserting into the master table, but not when inserting into > the child table. The easiest way to reproduce this is: > > jue=> create table ptest (a int, b int) partition by list (a); > CREATE TABLE > jue=> create table ptest1 partition of ptest (b default 7) for values in > (1); > CREATE TABLE > jue=> insert into ptest (a) values (1); > INSERT 0 1 > jue=> table ptest; > a | b > ---+--- > 1 | > (1 row) > > jue=> insert into ptest1 (a) values (1); > INSERT 0 1 > jue=> table ptest; > a | b > ---+--- > 1 | > 1 | 7 > (2 rows) > > The same happens for defaults using nextval(sequence), either if specified > directly or as SERIAL columns with ALTER TABLE ... ATTACH PARTITION. Hmm, so we provide the ability to specify default values per partition, but it is not applied when inserting through the parent. I'd like to hear from others on whether we should fix things so that we fill the partition's default value for a given column if it's null in the input tuple, after that tuple is routed to that partition. It does seem like a inconvenience to have to do it through workarounds like a BR trigger. Actually, default value substitution happens much earlier in the query rewrite phase, whereas the partition to actually insert the tuple into (that is, tuple routing) is determined much later during the execution of the query. So fixing this will require some work. > Second, this is a way to violate a NOT NULL constraint, presumably because a > default value should be applied later but isn't: > > jue=> create table ptest (a int, b int not null) partition by list (a); > CREATE TABLE > jue=> create table ptest1 partition of ptest (b default 7) for values in > (1); > CREATE TABLE > jue=> insert into ptest (a) values (1); > INSERT 0 1 > jue=> select * from ptest where b is null; > a | b > ---+--- > 1 | > (1 row) This is clearly a bug of CREATE TABLE .. PARTITION OF. It seems that the parent's NOT NULL constraint is not copied to the partition when a clause to set other column options, such as default 7 above, is used in the command to create a partition. It *is* successfully copied when such a clause is not specified. For example, same example but without the default value clause will lead to correct behavior wrt NOT NULL constraint. create table p (a int, b int not null) partition by list (a); -- note there is no (b default 7) clause being used here create table p1 partition of p for values in (1); -- NOT NULL constraint is correctly enforced insert into p values (1); ERROR: null value in column "b" violates not-null constraint DETAIL: Failing row contains (1, null). Attached patches fix that for PG 10 (patch filename starting with PG10-) and HEAD branches, respectively. Thanks, Amit
Attachment
Re: BUG #15212: Default values in partition tables don't work asexpected and allow NOT NULL violation
From
Dmitry Dolgov
Date:
> On 6 June 2018 at 10:00, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote: > Hello. > > On 2018/05/28 9:30, PG Bug reporting form wrote: >> The following bug has been logged on the website: >> >> Bug reference: 15212 >> Logged by: Jürgen Strobel >> Email address: juergen+postgresql@strobel.info >> PostgreSQL version: 10.4 >> Operating system: Debian >> Description: >> >> I found unexpected behavior when playing around with declarative >> partitioning. >> First, any way to define defaults on (child) partition tables is silently >> ignored when inserting into the master table, but not when inserting into >> the child table. > > Hmm, so we provide the ability to specify default values per partition, > but it is not applied when inserting through the parent. I'd like to hear > from others on whether we should fix things so that we fill the > partition's default value for a given column if it's null in the input > tuple, after that tuple is routed to that partition. It does seem like a > inconvenience to have to do it through workarounds like a BR trigger. > > Actually, default value substitution happens much earlier in the query > rewrite phase, whereas the partition to actually insert the tuple into > (that is, tuple routing) is determined much later during the execution of > the query. So fixing this will require some work. Well, since documentation says that partitioning build on top of inheritance, and for inheritance: If the new table explicitly specifies a default value for the column, this default overrides any defaults from inherited declarations of the column. So one may think it should be the same for partitioning as well.
Re: BUG #15212: Default values in partition tables don't work asexpected and allow NOT NULL violation
From
Dmitry Dolgov
Date:
> On 7 June 2018 at 15:53, Dmitry Dolgov <9erthalion6@gmail.com> wrote: >> On 6 June 2018 at 10:00, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote: >> Hello. >> >> On 2018/05/28 9:30, PG Bug reporting form wrote: >>> The following bug has been logged on the website: >>> >>> Bug reference: 15212 >>> Logged by: Jürgen Strobel >>> Email address: juergen+postgresql@strobel.info >>> PostgreSQL version: 10.4 >>> Operating system: Debian >>> Description: >>> >>> I found unexpected behavior when playing around with declarative >>> partitioning. >>> First, any way to define defaults on (child) partition tables is silently >>> ignored when inserting into the master table, but not when inserting into >>> the child table. >> >> Hmm, so we provide the ability to specify default values per partition, >> but it is not applied when inserting through the parent. I'd like to hear >> from others on whether we should fix things so that we fill the >> partition's default value for a given column if it's null in the input >> tuple, after that tuple is routed to that partition. It does seem like a >> inconvenience to have to do it through workarounds like a BR trigger. >> >> Actually, default value substitution happens much earlier in the query >> rewrite phase, whereas the partition to actually insert the tuple into >> (that is, tuple routing) is determined much later during the execution of >> the query. So fixing this will require some work. > > Well, since documentation says that partitioning build on top of inheritance, > and for inheritance: > > If the new table explicitly specifies a default value for the column, this > default overrides any defaults from inherited declarations of the column. > > So one may think it should be the same for partitioning as well. "The same for partitioning" - I mean the same approach when in all the situations (whether it's an insert into a parent table or a partition) a partition default value will take precedence.
Re: BUG #15212: Default values in partition tables don't work asexpected and allow NOT NULL violation
From
Amit Langote
Date:
Hi. On 2018/06/07 23:08, Dmitry Dolgov wrote: >> On 7 June 2018 at 15:53, Dmitry Dolgov <9erthalion6@gmail.com> wrote: >>> On 6 June 2018 at 10:00, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote: >>> On 2018/05/28 9:30, PG Bug reporting form wrote: >>>> The following bug has been logged on the website: >>>> >>>> Bug reference: 15212 >>>> Logged by: Jürgen Strobel >>>> Email address: juergen+postgresql@strobel.info >>>> PostgreSQL version: 10.4 >>>> Operating system: Debian >>>> Description: >>>> >>>> I found unexpected behavior when playing around with declarative >>>> partitioning. >>>> First, any way to define defaults on (child) partition tables is silently >>>> ignored when inserting into the master table, but not when inserting into >>>> the child table. >>> >>> Hmm, so we provide the ability to specify default values per partition, >>> but it is not applied when inserting through the parent. I'd like to hear >>> from others on whether we should fix things so that we fill the >>> partition's default value for a given column if it's null in the input >>> tuple, after that tuple is routed to that partition. It does seem like a >>> inconvenience to have to do it through workarounds like a BR trigger. >>> >>> Actually, default value substitution happens much earlier in the query >>> rewrite phase, whereas the partition to actually insert the tuple into >>> (that is, tuple routing) is determined much later during the execution of >>> the query. So fixing this will require some work. >> >> Well, since documentation says that partitioning build on top of inheritance, >> and for inheritance: >> >> If the new table explicitly specifies a default value for the column, this >> default overrides any defaults from inherited declarations of the column. >> >> So one may think it should be the same for partitioning as well. > > "The same for partitioning" - I mean the same approach when in all the > situations (whether it's an insert into a parent table or a partition) a > partition default value will take precedence. I think you have a point. Before partitioning, one would either insert directly into the child table or use a trigger to redirect an insert on parent into one of the child tables. In both cases, child table's default value would be used, because the insert query would mention the child table name. With partitioning, inserts into parent are internally handled in a way that bypasses the processing which would otherwise fill a partition's own default values for columns whose value is missing in the input row. That said, I'd like to make sure before writing a patch if the feature of being able to set defaults on partition level is something that users will want in the long run. Thanks, Amit
Re: BUG #15212: Default values in partition tables don't work asexpected and allow NOT NULL violation
From
Jürgen Strobel
Date:
On 06/13/2018 11:42 AM, Amit Langote wrote: > Hi. > > On 2018/06/07 23:08, Dmitry Dolgov wrote: >>> On 7 June 2018 at 15:53, Dmitry Dolgov <9erthalion6@gmail.com> wrote: >>>> On 6 June 2018 at 10:00, Amit Langote <Langote_Amit_f8@lab.ntt.co.jp> wrote: >>>> On 2018/05/28 9:30, PG Bug reporting form wrote: >>>>> The following bug has been logged on the website: >>>>> >>>>> Bug reference: 15212 >>>>> Logged by: Jürgen Strobel >>>>> Email address: juergen+postgresql@strobel.info >>>>> PostgreSQL version: 10.4 >>>>> Operating system: Debian >>>>> Description: >>>>> >>>>> I found unexpected behavior when playing around with declarative >>>>> partitioning. >>>>> First, any way to define defaults on (child) partition tables is silently >>>>> ignored when inserting into the master table, but not when inserting into >>>>> the child table. ... >>> >>> Well, since documentation says that partitioning build on top of inheritance, >>> and for inheritance: >>> >>> If the new table explicitly specifies a default value for the column, this >>> default overrides any defaults from inherited declarations of the column. >>> >>> So one may think it should be the same for partitioning as well. >> >> "The same for partitioning" - I mean the same approach when in all the >> situations (whether it's an insert into a parent table or a partition) a >> partition default value will take precedence. > > I think you have a point. Before partitioning, one would either insert > directly into the child table or use a trigger to redirect an insert on > parent into one of the child tables. In both cases, child table's default > value would be used, because the insert query would mention the child > table name. > > With partitioning, inserts into parent are internally handled in a way > that bypasses the processing which would otherwise fill a partition's own > default values for columns whose value is missing in the input row. > > That said, I'd like to make sure before writing a patch if the feature of > being able to set defaults on partition level is something that users will > want in the long run. > > Thanks, > Amit > I agree, and I imagine especially being able to use per-partition sequences would be a common use case. That was my motivation when I discovered it, and it was very counter intuitive to me. Thanks for the NULL violation patch btw. Best regards, Jürgen
Attachment
Re: BUG #15212: Default values in partition tables don't work asexpected and allow NOT NULL violation
From
Michael Paquier
Date:
On Wed, Jun 13, 2018 at 03:39:04PM +0200, Jürgen Strobel wrote: > I agree, and I imagine especially being able to use per-partition > sequences would be a common use case. That was my motivation when I > discovered it, and it was very counter intuitive to me. > > Thanks for the NULL violation patch btw. Please note that I have added this thread to the Open item page, under the older bug queue, and that a CF entry has been added so as we don't lost track of it: https://commitfest.postgresql.org/18/1671/ -- Michael
Attachment
Re: BUG #15212: Default values in partition tables don't work asexpected and allow NOT NULL violation
From
Amit Langote
Date:
On 2018/06/14 10:57, Michael Paquier wrote: > On Wed, Jun 13, 2018 at 03:39:04PM +0200, Jürgen Strobel wrote: >> I agree, and I imagine especially being able to use per-partition >> sequences would be a common use case. That was my motivation when I >> discovered it, and it was very counter intuitive to me. >> >> Thanks for the NULL violation patch btw. > > Please note that I have added this thread to the Open item page, under > the older bug queue, and that a CF entry has been added so as we don't > lost track of it: > > https://commitfest.postgresql.org/18/1671/ Thank you, Michael. Just to be sure, you meant to add the open item for the NOT NULL violation bug fix patch mainly or all of what appears to be wrong here? About partition-specific defaults being ignored when inserting through the parent, do you think we should consider it a bug? I could imagine fixing the documentation to say that partition-specific defaults are only honored if directly inserted into and ignored otherwise. Thanks, Amit