diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c index 8219d05d83..75e41ed21c 100644 --- a/src/backend/catalog/partition.c +++ b/src/backend/catalog/partition.c @@ -195,23 +195,12 @@ RelationBuildPartitionDesc(Relation rel) if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for relation %u", inhrelid); - /* - * It is possible that the pg_class tuple of a partition has not been - * updated yet to set its relpartbound field. The only case where - * this happens is when we open the parent relation to check using its - * partition descriptor that a new partition's bound does not overlap - * some existing partition. - */ - if (!((Form_pg_class) GETSTRUCT(tuple))->relispartition) - { - ReleaseSysCache(tuple); - continue; - } - datum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound, &isnull); - Assert(!isnull); + if(isnull) + elog(ERROR, "null relpartbound for relation %u", inhrelid); + boundspec = (Node *) stringToNode(TextDatumGetCString(datum)); boundspecs = lappend(boundspecs, boundspec); partoids = lappend_oid(partoids, inhrelid); @@ -1856,8 +1845,7 @@ generate_partition_qual(Relation rel) Anum_pg_class_relpartbound, &isnull); if (isnull) /* should not happen */ - elog(ERROR, "relation \"%s\" has relpartbound = null", - RelationGetRelationName(rel)); + elog(ERROR, "null relpartbound for relation %u", RelationGetRelid(rel)); bound = castNode(PartitionBoundSpec, stringToNode(TextDatumGetCString(boundDatum))); ReleaseSysCache(tuple); diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index f143101b5d..43b76812d2 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -745,9 +745,6 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, false, typaddress); - /* Store inheritance information for new rel. */ - StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL); - /* * We must bump the command counter to make the newly-created relation * tuple visible for opening. @@ -809,6 +806,9 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, CommandCounterIncrement(); } + /* Store inheritance information for new rel. */ + StoreCatalogInheritance(relationId, inheritOids, stmt->partbound != NULL); + /* * Process the partitioning specification (if any) and store the partition * key information into the catalog. @@ -13611,9 +13611,6 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd) trigger_name, RelationGetRelationName(attachrel)), errdetail("ROW triggers with transition tables are not supported on partitions"))); - /* OK to create inheritance. Rest of the checks performed there */ - CreateInheritance(attachrel, rel); - /* * Check that the new partition's bound is valid and does not overlap any * of existing partitions of the parent - note that it does not return on @@ -13622,6 +13619,9 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd) check_new_partition_bound(RelationGetRelationName(attachrel), rel, cmd->bound); + /* OK to create inheritance. Rest of the checks performed there */ + CreateInheritance(attachrel, rel); + /* Update the pg_class entry. */ StorePartitionBound(attachrel, rel, cmd->bound); @@ -13837,10 +13837,6 @@ ATExecDetachPartition(Relation rel, RangeVar *name) RelationGetRelid(partRel)); Assert(((Form_pg_class) GETSTRUCT(tuple))->relispartition); - (void) SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relpartbound, - &isnull); - Assert(!isnull); - /* Clear relpartbound and reset relispartition */ memset(new_val, 0, sizeof(new_val)); memset(new_null, false, sizeof(new_null)); diff --git a/src/test/regress/expected/alter_table.out b/src/test/regress/expected/alter_table.out index 86127ce0df..bd3f918e48 100644 --- a/src/test/regress/expected/alter_table.out +++ b/src/test/regress/expected/alter_table.out @@ -3669,3 +3669,18 @@ alter table temp_part_parent attach partition temp_part_child for values in (1, 2); -- ok drop table perm_part_parent cascade; drop table temp_part_parent cascade; +-- test case where the partitioning operator is a SQL function whose +-- evaluation results in the table's relcache being rebuilt partway through +-- the execution of an ATTACH PARTITION command +create function at_test_sql_partop (int4, int4) returns int language sql +as $$ select case when $1 = $2 then 0 when $1 > $2 then 1 else -1 end; $$; +create operator class at_test_sql_partop for type int4 using btree as + operator 1 < (int4, int4), operator 2 <= (int4, int4), + operator 3 = (int4, int4), operator 4 >= (int4, int4), + operator 5 > (int4, int4), function 1 at_test_sql_partop(int4, int4); +create table at_test_sql_partop (a int) partition by range (a at_test_sql_partop); +create table at_test_sql_partop_1 (a int); +alter table at_test_sql_partop attach partition at_test_sql_partop_1 for values from (0) to (10); +drop table at_test_sql_partop; +drop operator class at_test_sql_partop using btree; +drop function at_test_sql_partop; diff --git a/src/test/regress/sql/alter_table.sql b/src/test/regress/sql/alter_table.sql index 519d984fd9..24b60f9b6e 100644 --- a/src/test/regress/sql/alter_table.sql +++ b/src/test/regress/sql/alter_table.sql @@ -2388,3 +2388,19 @@ alter table temp_part_parent attach partition temp_part_child for values in (1, 2); -- ok drop table perm_part_parent cascade; drop table temp_part_parent cascade; + +-- test case where the partitioning operator is a SQL function whose +-- evaluation results in the table's relcache being rebuilt partway through +-- the execution of an ATTACH PARTITION command +create function at_test_sql_partop (int4, int4) returns int language sql +as $$ select case when $1 = $2 then 0 when $1 > $2 then 1 else -1 end; $$; +create operator class at_test_sql_partop for type int4 using btree as + operator 1 < (int4, int4), operator 2 <= (int4, int4), + operator 3 = (int4, int4), operator 4 >= (int4, int4), + operator 5 > (int4, int4), function 1 at_test_sql_partop(int4, int4); +create table at_test_sql_partop (a int) partition by range (a at_test_sql_partop); +create table at_test_sql_partop_1 (a int); +alter table at_test_sql_partop attach partition at_test_sql_partop_1 for values from (0) to (10); +drop table at_test_sql_partop; +drop operator class at_test_sql_partop using btree; +drop function at_test_sql_partop;