public inbox for [email protected]
help / color / mirror / Atom feedFrom: Alvaro Herrera <[email protected]>
Subject: [PATCH 2/2] Propagate replica identity to partitions
Date: Mon, 4 Feb 2019 13:43:58 -0300
---
src/backend/commands/tablecmds.c | 59 +++++++++++++--
src/bin/psql/describe.c | 3 +-
src/test/regress/expected/replica_identity.out | 99 ++++++++++++++++++++++++++
src/test/regress/sql/replica_identity.sql | 33 +++++++++
4 files changed, 189 insertions(+), 5 deletions(-)
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 877bac506f..4b2ae01f15 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -300,7 +300,7 @@ static void truncate_check_activity(Relation rel);
static void RangeVarCallbackForTruncate(const RangeVar *relation,
Oid relId, Oid oldRelId, void *arg);
static List *MergeAttributes(List *schema, List *supers, char relpersistence,
- bool is_partition, List **supconstr);
+ bool is_partition, List **supconstr, char *ri_type);
static bool MergeCheckConstraint(List *constraints, char *name, Node *expr);
static void MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel);
static void MergeConstraintsIntoExisting(Relation child_rel, Relation parent_rel);
@@ -485,6 +485,7 @@ static void AttachPartitionEnsureIndexes(Relation rel, Relation attachrel);
static void QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
List *partConstraint,
bool validate_default);
+static void MatchReplicaIdentity(Relation tgtrel, Relation srcrel);
static void CloneRowTriggersToPartition(Relation parent, Relation partition);
static ObjectAddress ATExecDetachPartition(Relation rel, RangeVar *name);
static ObjectAddress ATExecAttachPartitionIdx(List **wqueue, Relation rel,
@@ -527,6 +528,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
TupleDesc descriptor;
List *inheritOids;
List *old_constraints;
+ char ri_type;
List *rawDefaults;
List *cookedDefaults;
Datum reloptions;
@@ -708,7 +710,7 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
MergeAttributes(stmt->tableElts, inheritOids,
stmt->relation->relpersistence,
stmt->partbound != NULL,
- &old_constraints);
+ &old_constraints, &ri_type);
/*
* Create a tuple descriptor from the relation schema. Note that this
@@ -1014,6 +1016,10 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId,
*/
CloneForeignKeyConstraints(parentId, relationId, NULL);
+ /* Propagate REPLICA IDENTITY information too */
+ if (ri_type != REPLICA_IDENTITY_DEFAULT)
+ MatchReplicaIdentity(rel, parent);
+
table_close(parent, NoLock);
}
@@ -1873,6 +1879,8 @@ storage_name(char c)
* Output arguments:
* 'supconstr' receives a list of constraints belonging to the parents,
* updated as necessary to be valid for the child.
+ * 'ri_type' receives the replica identity type of the last parent seen,
+ * or default if none.
*
* Return value:
* Completed schema list.
@@ -1914,11 +1922,15 @@ storage_name(char c)
* (4) Otherwise the inherited default is used.
* Rule (3) is new in Postgres 7.1; in earlier releases you got a
* rather arbitrary choice of which parent default to use.
+ *
+ * It only makes sense to use the returned 'ri_type' when there's a single
+ * parent, such as in declarative partitioning.
*----------
*/
static List *
MergeAttributes(List *schema, List *supers, char relpersistence,
- bool is_partition, List **supconstr)
+ bool is_partition, List **supconstr,
+ char *ri_type)
{
ListCell *entry;
List *inhSchema = NIL;
@@ -2015,6 +2027,11 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
}
/*
+ * Initialize replica identity to default; parents may change it later
+ */
+ *ri_type = REPLICA_IDENTITY_DEFAULT;
+
+ /*
* Scan the parents left-to-right, and merge their attributes to form a
* list of inherited attributes (inhSchema). Also check to see if we need
* to inherit an OID column.
@@ -2095,6 +2112,9 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
? "cannot inherit from temporary relation of another session"
: "cannot create as partition of temporary relation of another session")));
+ /* Indicate replica identity back to caller */
+ *ri_type = relation->rd_rel->relreplident;
+
/*
* We should have an UNDER permission flag for this, but for now,
* demand that creator of a child table own the parent.
@@ -3935,7 +3955,9 @@ ATPrepCmd(List **wqueue, Relation rel, AlterTableCmd *cmd,
case AT_ReplicaIdentity: /* REPLICA IDENTITY ... */
ATSimplePermissions(rel, ATT_TABLE | ATT_MATVIEW);
pass = AT_PASS_MISC;
- /* This command never recurses */
+ /* Recurse only on partitioned tables */
+ if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ ATSimpleRecursion(wqueue, rel, cmd, recurse, lockmode);
/* No command-specific prep needed */
break;
case AT_EnableTrig: /* ENABLE TRIGGER variants */
@@ -14664,6 +14686,10 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
/* and triggers */
CloneRowTriggersToPartition(rel, attachrel);
+ /* Propagate REPLICA IDENTITY information */
+ if (rel->rd_rel->relreplident != REPLICA_IDENTITY_DEFAULT)
+ MatchReplicaIdentity(attachrel, rel);
+
/*
* Clone foreign key constraints, and setup for Phase 3 to verify them.
*/
@@ -14915,6 +14941,31 @@ AttachPartitionEnsureIndexes(Relation rel, Relation attachrel)
}
/*
+ * Set up partRel's (a partition) replica identity to match parentRel's (its
+ * parent).
+ */
+static void
+MatchReplicaIdentity(Relation partRel, Relation srcrel)
+{
+ Oid ri_index;
+
+ if (srcrel->rd_rel->relreplident == REPLICA_IDENTITY_INDEX)
+ {
+ ri_index = index_get_partition(partRel,
+ RelationGetReplicaIndex(srcrel));
+ if (!OidIsValid(ri_index))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("replica index does not exist in partition")));
+ }
+ else
+ ri_index = InvalidOid;
+
+ relation_mark_replica_identity(partRel, srcrel->rd_rel->relreplident,
+ ri_index, true);
+}
+
+/*
* CloneRowTriggersToPartition
* subroutine for ATExecAttachPartition/DefineRelation to create row
* triggers on partitions
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 4da6719ce7..6145a000cb 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -3113,7 +3113,8 @@ describeOneTableDetails(const char *schemaname,
if (verbose &&
(tableinfo.relkind == RELKIND_RELATION ||
- tableinfo.relkind == RELKIND_MATVIEW) &&
+ tableinfo.relkind == RELKIND_MATVIEW ||
+ tableinfo.relkind == RELKIND_PARTITIONED_TABLE) &&
/*
* No need to display default values; we already display a REPLICA
diff --git a/src/test/regress/expected/replica_identity.out b/src/test/regress/expected/replica_identity.out
index 175ecd2879..3051cf1551 100644
--- a/src/test/regress/expected/replica_identity.out
+++ b/src/test/regress/expected/replica_identity.out
@@ -181,3 +181,102 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
DROP TABLE test_replica_identity;
DROP TABLE test_replica_identity_othertable;
+----
+-- Make sure it propagates to partitions
+----
+CREATE TABLE test_replica_identity_part (a int, b int) PARTITION BY RANGE (a);
+CREATE TABLE test_replica_identity_part1 PARTITION OF test_replica_identity_part
+ FOR VALUES FROM (0) TO (1000) PARTITION BY RANGE (a);
+CREATE TABLE test_replica_identity_part2 PARTITION OF test_replica_identity_part
+ FOR VALUES FROM (1000) TO (2000);
+CREATE TABLE test_replica_identity_part11 PARTITION OF test_replica_identity_part1
+ FOR VALUES FROM (1000) TO (1500);
+ALTER TABLE test_replica_identity_part REPLICA IDENTITY FULL;
+CREATE TABLE test_replica_identity_part3 PARTITION OF test_replica_identity_part
+ FOR VALUES FROM (2000) TO (3000);
+CREATE TABLE test_replica_identity_part4 (LIKE test_replica_identity_part);
+ALTER TABLE test_replica_identity_part ATTACH PARTITION test_replica_identity_part4
+ FOR VALUES FROM (3000) TO (4000);
+\d+ test_replica_identity_part2
+ Table "public.test_replica_identity_part2"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a | integer | | | | plain | |
+ b | integer | | | | plain | |
+Partition of: test_replica_identity_part FOR VALUES FROM (1000) TO (2000)
+Partition constraint: ((a IS NOT NULL) AND (a >= 1000) AND (a < 2000))
+Replica Identity: FULL
+
+\d+ test_replica_identity_part11
+ Table "public.test_replica_identity_part11"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a | integer | | | | plain | |
+ b | integer | | | | plain | |
+Partition of: test_replica_identity_part1 FOR VALUES FROM (1000) TO (1500)
+Partition constraint: ((a IS NOT NULL) AND (a >= 0) AND (a < 1000) AND (a IS NOT NULL) AND (a >= 1000) AND (a < 1500))
+Replica Identity: FULL
+
+\d+ test_replica_identity_part
+ Partitioned table "public.test_replica_identity_part"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a | integer | | | | plain | |
+ b | integer | | | | plain | |
+Partition key: RANGE (a)
+Partitions: test_replica_identity_part1 FOR VALUES FROM (0) TO (1000), PARTITIONED,
+ test_replica_identity_part2 FOR VALUES FROM (1000) TO (2000),
+ test_replica_identity_part3 FOR VALUES FROM (2000) TO (3000),
+ test_replica_identity_part4 FOR VALUES FROM (3000) TO (4000)
+Replica Identity: FULL
+
+\d+ test_replica_identity_part3
+ Table "public.test_replica_identity_part3"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a | integer | | | | plain | |
+ b | integer | | | | plain | |
+Partition of: test_replica_identity_part FOR VALUES FROM (2000) TO (3000)
+Partition constraint: ((a IS NOT NULL) AND (a >= 2000) AND (a < 3000))
+Replica Identity: FULL
+
+\d+ test_replica_identity_part4
+ Table "public.test_replica_identity_part4"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a | integer | | | | plain | |
+ b | integer | | | | plain | |
+Partition of: test_replica_identity_part FOR VALUES FROM (3000) TO (4000)
+Partition constraint: ((a IS NOT NULL) AND (a >= 3000) AND (a < 4000))
+Replica Identity: FULL
+
+----
+-- Check behavior with inherited tables
+----
+CREATE TABLE test_replica_identity_inh (a int);
+CREATE TABLE test_replica_identity_cld () INHERITS (test_replica_identity_inh);
+ALTER TABLE test_replica_identity_inh REPLICA IDENTITY FULL;
+CREATE TABLE test_replica_identity_cld2 () INHERITS (test_replica_identity_inh);
+\d+ test_replica_identity_inh
+ Table "public.test_replica_identity_inh"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a | integer | | | | plain | |
+Child tables: test_replica_identity_cld,
+ test_replica_identity_cld2
+Replica Identity: FULL
+
+\d+ test_replica_identity_cld
+ Table "public.test_replica_identity_cld"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a | integer | | | | plain | |
+Inherits: test_replica_identity_inh
+
+\d+ test_replica_identity_cld2
+ Table "public.test_replica_identity_cld2"
+ Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
+--------+---------+-----------+----------+---------+---------+--------------+-------------
+ a | integer | | | | plain | |
+Inherits: test_replica_identity_inh
+
diff --git a/src/test/regress/sql/replica_identity.sql b/src/test/regress/sql/replica_identity.sql
index b08a3623b8..a567f2b52d 100644
--- a/src/test/regress/sql/replica_identity.sql
+++ b/src/test/regress/sql/replica_identity.sql
@@ -77,3 +77,36 @@ SELECT relreplident FROM pg_class WHERE oid = 'test_replica_identity'::regclass;
DROP TABLE test_replica_identity;
DROP TABLE test_replica_identity_othertable;
+
+----
+-- Make sure it propagates to partitions
+----
+CREATE TABLE test_replica_identity_part (a int, b int) PARTITION BY RANGE (a);
+CREATE TABLE test_replica_identity_part1 PARTITION OF test_replica_identity_part
+ FOR VALUES FROM (0) TO (1000) PARTITION BY RANGE (a);
+CREATE TABLE test_replica_identity_part2 PARTITION OF test_replica_identity_part
+ FOR VALUES FROM (1000) TO (2000);
+CREATE TABLE test_replica_identity_part11 PARTITION OF test_replica_identity_part1
+ FOR VALUES FROM (1000) TO (1500);
+ALTER TABLE test_replica_identity_part REPLICA IDENTITY FULL;
+CREATE TABLE test_replica_identity_part3 PARTITION OF test_replica_identity_part
+ FOR VALUES FROM (2000) TO (3000);
+CREATE TABLE test_replica_identity_part4 (LIKE test_replica_identity_part);
+ALTER TABLE test_replica_identity_part ATTACH PARTITION test_replica_identity_part4
+ FOR VALUES FROM (3000) TO (4000);
+\d+ test_replica_identity_part2
+\d+ test_replica_identity_part11
+\d+ test_replica_identity_part
+\d+ test_replica_identity_part3
+\d+ test_replica_identity_part4
+
+----
+-- Check behavior with inherited tables
+----
+CREATE TABLE test_replica_identity_inh (a int);
+CREATE TABLE test_replica_identity_cld () INHERITS (test_replica_identity_inh);
+ALTER TABLE test_replica_identity_inh REPLICA IDENTITY FULL;
+CREATE TABLE test_replica_identity_cld2 () INHERITS (test_replica_identity_inh);
+\d+ test_replica_identity_inh
+\d+ test_replica_identity_cld
+\d+ test_replica_identity_cld2
--
2.11.0
--gy7na3sjffpqghel--
view thread (77+ messages) latest in thread
reply
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Reply to all the recipients using the --to and --cc options:
reply via email
To: [email protected]
Cc: [email protected]
Subject: Re: [PATCH 2/2] Propagate replica identity to partitions
In-Reply-To: <no-message-id-1883427@localhost>
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox