odd behaviour with serial, non null and partitioned table

Поиск
Список
Период
Сортировка
От Ashutosh Bapat
Тема odd behaviour with serial, non null and partitioned table
Дата
Msg-id CAExHW5uRUtDfU0R8zXofQxCV3S1B+Pa+X+NrpMwzKraLc25=Eg@mail.gmail.com
обсуждение исходный текст
Ответы Re: odd behaviour with serial, non null and partitioned table
Список pgsql-hackers
Hi Alvaro,

Problem 1
========
#create table tpart (a serial primary key, src varchar) partition by range(a);
CREATE TABLE
#create table t_p4 (a int primary key, src varchar);
CREATE TABLE
#\d tpart
                           Partitioned table "public.tpart"
 Column |       Type        | Collation | Nullable |
Default
--------+-------------------+-----------+----------+----------------------------------
 a      | integer           |           | not null |
nextval('tpart_a_seq'::regclass)
 src    | character varying |           |          |
Partition key: RANGE (a)
Indexes:
    "tpart_pkey" PRIMARY KEY, btree (a)
Number of partitions: 0

#\d t_p4;
                     Table "public.t_p4"
 Column |       Type        | Collation | Nullable | Default
--------+-------------------+-----------+----------+---------
 a      | integer           |           | not null |
 src    | character varying |           |          |
Indexes:
    "t_p4_pkey" PRIMARY KEY, btree (a)

Notice that both tpart and t_p4 have their column 'a' marked NOT NULL resp.

#select conname, contype, conrelid::regclass from pg_constraint where
conrelid in ('tpart'::regclass, 't_p4'::regclass);
     conname      | contype | conrelid
------------------+---------+----------
 tpart_a_not_null | n       | tpart
 tpart_pkey       | p       | tpart
 t_p4_pkey        | p       | t_p4
(3 rows)

But tparts NOT NULL constraint is recorded in pg_constraint but not
t_p4's. Is this expected?

Both of them have there column a marked not null in pg_attribute
#select attrelid::regclass, attname, attnotnull from pg_attribute
where attrelid in ('tpart'::regclass, 't_p4'::regclass) and attname =
'a';
 attrelid | attname | attnotnull
----------+---------+------------
 tpart   | a       | t
 t_p4     | a       | t
(2 rows)

From the next set of commands it can be inferred that the NOT NULL
constraint of tpart came because of serial column whereas t_p4's
column a was marked NOT NULL because of primary key. I didn't
investigate the source code.
#create table t_serial(a serial, src varchar);
CREATE TABLE
#select conname, contype, conrelid::regclass from pg_constraint where
conrelid in ('t_serial'::regclass);
       conname       | contype | conrelid
---------------------+---------+----------
 t_serial_a_not_null | n       | t_serial
(1 row)

#select attrelid::regclass, attname, attnotnull from pg_attribute
where attrelid in ('t_serial'::regclass) and attname = 'a';
 attrelid | attname | attnotnull
----------+---------+------------
 t_serial | a       | t
(1 row)

Here's what I was trying to do actually.
#alter table tpart attach partition t_p4 for values from (7) to (9);
ERROR:  column "a" in child table must be marked NOT NULL
This is a surprise since t_p4.a is marked as NOT NULL. That happens
because MergeConstraintsIntoExisting() only looks at pg_constraint and
not pg_attribute. Should this function look at pg_attribute as well?

This behaviour is different from PG 14. I chanced to have a PG 14
build and hence tried that. I haven't tried PG 15 though.
#select version();
                                                version
-------------------------------------------------------------------------------------------------------
 PostgreSQL 14.8 on x86_64-pc-linux-gnu, compiled by gcc (Ubuntu
9.4.0-1ubuntu1~20.04.1) 9.4.0, 64-bit
(1 row)

#create table tpart (a serial primary key, src varchar) partition by range(a);
CREATE TABLE
#create table t_p4 (a int primary key, src varchar);
CREATE TABLE
#\d tpart
                           Partitioned table "public.tpart"
 Column |       Type        | Collation | Nullable |
Default
--------+-------------------+-----------+----------+----------------------------------
 a      | integer           |           | not null |
nextval('tpart_a_seq'::regclass)
 src    | character varying |           |          |
Partition key: RANGE (a)
Indexes:
    "tpart_pkey" PRIMARY KEY, btree (a)
Number of partitions: 0

#\d t_p4
                     Table "public.t_p4"
 Column |       Type        | Collation | Nullable | Default
--------+-------------------+-----------+----------+---------
 a      | integer           |           | not null |
 src    | character varying |           |          |
Indexes:
    "t_p4_pkey" PRIMARY KEY, btree (a)

#select conname, contype, conrelid::regclass from pg_constraint where
conrelid in ('tpart'::regclass, 't_p4'::regclass);
  conname   | contype | conrelid
------------+---------+----------
 tpart_pkey | p       | tpart
 t_p4_pkey  | p       | t_p4
(2 rows)
                                                             ^
#select attrelid::regclass, attname, attnotnull from pg_attribute
where attrelid in ('tpart'::regclass, 't_p4'::regclass) and attname =
'a';
 attrelid | attname | attnotnull
----------+---------+------------
 tpart    | a       | t
 t_p4     | a       | t
(2 rows)

#alter table tpart attach partition t_p4 for values from (7) to (9);
ALTER TABLE
postgres@1073836=#\d tpart
                           Partitioned table "public.tpart"
 Column |       Type        | Collation | Nullable |
Default
--------+-------------------+-----------+----------+----------------------------------
 a      | integer           |           | not null |
nextval('tpart_a_seq'::regclass)
 src    | character varying |           |          |
Partition key: RANGE (a)
Indexes:
    "tpart_pkey" PRIMARY KEY, btree (a)
Number of partitions: 1 (Use \d+ to list them.)

#\d t_p4
                     Table "public.t_p4"
 Column |       Type        | Collation | Nullable | Default
--------+-------------------+-----------+----------+---------
 a      | integer           |           | not null |
 src    | character varying |           |          |
Partition of: tpart FOR VALUES FROM (7) TO (9)
Indexes:
    "t_p4_pkey" PRIMARY KEY, btree (a)

Notice that ALTER TABLE succeeded and t_p4 was attached to tpart as a partition.

Is this backward compatibility break intentional? I haven't followed
NOT NULL constraint thread closely. I might have missed some
discussion.

-- 
Best Wishes,
Ashutosh Bapat



В списке pgsql-hackers по дате отправления:

Предыдущее
От: Pavel Stehule
Дата:
Сообщение: Re: Schema variables - new implementation for Postgres 15
Следующее
От: "Anton A. Melnikov"
Дата:
Сообщение: Re: remaining sql/json patches