Commit 34229557 authored by Michael Paquier's avatar Michael Paquier

Consider only relations part of partition trees in partition functions

This changes the partition functions so as tables and indexes which are
not part of partition trees are handled the same way as what is done for
undefined objects and unsupported relkinds: pg_partition_tree() returns
no rows and pg_partition_root() returns a NULL result.  Hence,
partitioned tables, partitioned indexes and relations whose flag
pg_class.relispartition is set are considered as valid objects to
process.

Previously, tables and indexes not included in a partition tree were
processed the same way as a partition or a partitioned table, which
caused the functions to return inconsistent results for inherited
tables, especially when inheriting from multiple tables.

Reported-by: Álvaro Herrera
Author: Amit Langote, Michael Paquier
Reviewed-by: Tom Lane
Discussion: https://postgr.es/m/20190228193203.GA26151@alvherre.pgsql
parent 70b9bda6
......@@ -35,17 +35,17 @@ static bool
check_rel_can_be_partition(Oid relid)
{
char relkind;
bool relispartition;
/* Check if relation exists */
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relid)))
return false;
relkind = get_rel_relkind(relid);
relispartition = get_rel_relispartition(relid);
/* Only allow relation types that can appear in partition trees. */
if (relkind != RELKIND_RELATION &&
relkind != RELKIND_FOREIGN_TABLE &&
relkind != RELKIND_INDEX &&
if (!relispartition &&
relkind != RELKIND_PARTITIONED_TABLE &&
relkind != RELKIND_PARTITIONED_INDEX)
return false;
......@@ -189,13 +189,6 @@ pg_partition_root(PG_FUNCTION_ARGS)
if (!check_rel_can_be_partition(relid))
PG_RETURN_NULL();
/*
* If the relation is not a partition (it may be the partition parent),
* return itself as a result.
*/
if (!get_rel_relispartition(relid))
PG_RETURN_OID(relid);
/* Fetch the top-most parent */
ancestors = get_partition_ancestors(relid);
rootrelid = llast_oid(ancestors);
......
......@@ -32,7 +32,10 @@ CREATE TABLE ptif_test1 PARTITION OF ptif_test
FOR VALUES FROM (0) TO (100) PARTITION BY list (b);
CREATE TABLE ptif_test11 PARTITION OF ptif_test1 FOR VALUES IN (1);
CREATE TABLE ptif_test2 PARTITION OF ptif_test
FOR VALUES FROM (100) TO (maxvalue);
FOR VALUES FROM (100) TO (200);
-- This partitioned table should remain with no partitions.
CREATE TABLE ptif_test3 PARTITION OF ptif_test
FOR VALUES FROM (200) TO (maxvalue) PARTITION BY list (b);
-- Test index partition tree
CREATE INDEX ptif_test_index ON ONLY ptif_test (a);
CREATE INDEX ptif_test0_index ON ONLY ptif_test0 (a);
......@@ -45,6 +48,8 @@ CREATE INDEX ptif_test11_index ON ptif_test11 (a);
ALTER INDEX ptif_test1_index ATTACH PARTITION ptif_test11_index;
CREATE INDEX ptif_test2_index ON ptif_test2 (a);
ALTER INDEX ptif_test_index ATTACH PARTITION ptif_test2_index;
CREATE INDEX ptif_test3_index ON ptif_test3 (a);
ALTER INDEX ptif_test_index ATTACH PARTITION ptif_test3_index;
-- List all tables members of the tree
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_test');
......@@ -54,9 +59,10 @@ SELECT relid, parentrelid, level, isleaf
ptif_test0 | ptif_test | 1 | f
ptif_test1 | ptif_test | 1 | f
ptif_test2 | ptif_test | 1 | t
ptif_test3 | ptif_test | 1 | f
ptif_test01 | ptif_test0 | 2 | t
ptif_test11 | ptif_test1 | 2 | t
(6 rows)
(7 rows)
-- List tables from an intermediate level
SELECT relid, parentrelid, level, isleaf
......@@ -77,6 +83,15 @@ SELECT relid, parentrelid, level, isleaf
ptif_test01 | ptif_test0 | 0 | t
(1 row)
-- List from partitioned table with no partitions
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_test3') p
JOIN pg_class c ON (p.relid = c.oid);
relid | parentrelid | level | isleaf
------------+-------------+-------+--------
ptif_test3 | ptif_test | 0 | f
(1 row)
-- List all members using pg_partition_root with leaf table reference
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree(pg_partition_root('ptif_test01')) p
......@@ -87,9 +102,10 @@ SELECT relid, parentrelid, level, isleaf
ptif_test0 | ptif_test | 1 | f
ptif_test1 | ptif_test | 1 | f
ptif_test2 | ptif_test | 1 | t
ptif_test3 | ptif_test | 1 | f
ptif_test01 | ptif_test0 | 2 | t
ptif_test11 | ptif_test1 | 2 | t
(6 rows)
(7 rows)
-- List all indexes members of the tree
SELECT relid, parentrelid, level, isleaf
......@@ -100,9 +116,10 @@ SELECT relid, parentrelid, level, isleaf
ptif_test0_index | ptif_test_index | 1 | f
ptif_test1_index | ptif_test_index | 1 | f
ptif_test2_index | ptif_test_index | 1 | t
ptif_test3_index | ptif_test_index | 1 | f
ptif_test01_index | ptif_test0_index | 2 | t
ptif_test11_index | ptif_test1_index | 2 | t
(6 rows)
(7 rows)
-- List indexes from an intermediate level
SELECT relid, parentrelid, level, isleaf
......@@ -123,6 +140,15 @@ SELECT relid, parentrelid, level, isleaf
ptif_test01_index | ptif_test0_index | 0 | t
(1 row)
-- List from partitioned index with no partitions
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_test3_index') p
JOIN pg_class c ON (p.relid = c.oid);
relid | parentrelid | level | isleaf
------------------+-----------------+-------+--------
ptif_test3_index | ptif_test_index | 0 | f
(1 row)
-- List all members using pg_partition_root with leaf index reference
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree(pg_partition_root('ptif_test01_index')) p
......@@ -133,24 +159,24 @@ SELECT relid, parentrelid, level, isleaf
ptif_test0_index | ptif_test_index | 1 | f
ptif_test1_index | ptif_test_index | 1 | f
ptif_test2_index | ptif_test_index | 1 | t
ptif_test3_index | ptif_test_index | 1 | f
ptif_test01_index | ptif_test0_index | 2 | t
ptif_test11_index | ptif_test1_index | 2 | t
(6 rows)
(7 rows)
DROP TABLE ptif_test;
-- Table that is not part of any partition tree is the only member listed.
-- Table that is not part of any partition tree is not listed.
CREATE TABLE ptif_normal_table(a int);
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_normal_table');
relid | parentrelid | level | isleaf
-------------------+-------------+-------+--------
ptif_normal_table | | 0 | t
(1 row)
relid | parentrelid | level | isleaf
-------+-------------+-------+--------
(0 rows)
SELECT pg_partition_root('ptif_normal_table');
pg_partition_root
-------------------
ptif_normal_table
(1 row)
DROP TABLE ptif_normal_table;
......
......@@ -15,7 +15,10 @@ CREATE TABLE ptif_test1 PARTITION OF ptif_test
FOR VALUES FROM (0) TO (100) PARTITION BY list (b);
CREATE TABLE ptif_test11 PARTITION OF ptif_test1 FOR VALUES IN (1);
CREATE TABLE ptif_test2 PARTITION OF ptif_test
FOR VALUES FROM (100) TO (maxvalue);
FOR VALUES FROM (100) TO (200);
-- This partitioned table should remain with no partitions.
CREATE TABLE ptif_test3 PARTITION OF ptif_test
FOR VALUES FROM (200) TO (maxvalue) PARTITION BY list (b);
-- Test index partition tree
CREATE INDEX ptif_test_index ON ONLY ptif_test (a);
......@@ -29,6 +32,8 @@ CREATE INDEX ptif_test11_index ON ptif_test11 (a);
ALTER INDEX ptif_test1_index ATTACH PARTITION ptif_test11_index;
CREATE INDEX ptif_test2_index ON ptif_test2 (a);
ALTER INDEX ptif_test_index ATTACH PARTITION ptif_test2_index;
CREATE INDEX ptif_test3_index ON ptif_test3 (a);
ALTER INDEX ptif_test_index ATTACH PARTITION ptif_test3_index;
-- List all tables members of the tree
SELECT relid, parentrelid, level, isleaf
......@@ -41,6 +46,10 @@ SELECT relid, parentrelid, level, isleaf
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_test01') p
JOIN pg_class c ON (p.relid = c.oid);
-- List from partitioned table with no partitions
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_test3') p
JOIN pg_class c ON (p.relid = c.oid);
-- List all members using pg_partition_root with leaf table reference
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree(pg_partition_root('ptif_test01')) p
......@@ -57,6 +66,10 @@ SELECT relid, parentrelid, level, isleaf
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_test01_index') p
JOIN pg_class c ON (p.relid = c.oid);
-- List from partitioned index with no partitions
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_test3_index') p
JOIN pg_class c ON (p.relid = c.oid);
-- List all members using pg_partition_root with leaf index reference
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree(pg_partition_root('ptif_test01_index')) p
......@@ -64,7 +77,7 @@ SELECT relid, parentrelid, level, isleaf
DROP TABLE ptif_test;
-- Table that is not part of any partition tree is the only member listed.
-- Table that is not part of any partition tree is not listed.
CREATE TABLE ptif_normal_table(a int);
SELECT relid, parentrelid, level, isleaf
FROM pg_partition_tree('ptif_normal_table');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment