ii = BuildIndexInfo(indexDesc);
/*
- * If the indexes are to be used for speculative insertion or conflict
- * detection in logical replication, add extra information required by
- * unique index entries.
+ * If the indexes are to be used for speculative insertion, add extra
+ * information required by unique index entries.
*/
if (speculative && ii->ii_Unique && !indexDesc->rd_index->indisexclusion)
BuildSpeculativeIndexInfo(indexDesc, ii);
return found;
}
+/*
+ * Build additional index information necessary for conflict detection.
+ */
+static void
+BuildConflictIndexInfo(ResultRelInfo *resultRelInfo, Oid conflictindex)
+{
+ for (int i = 0; i < resultRelInfo->ri_NumIndices; i++)
+ {
+ Relation indexRelation = resultRelInfo->ri_IndexRelationDescs[i];
+ IndexInfo *indexRelationInfo = resultRelInfo->ri_IndexRelationInfo[i];
+
+ if (conflictindex != RelationGetRelid(indexRelation))
+ continue;
+
+ /*
+ * This Assert will fail if BuildSpeculativeIndexInfo() is called
+ * twice for the given index.
+ */
+ Assert(indexRelationInfo->ii_UniqueOps == NULL);
+
+ BuildSpeculativeIndexInfo(indexRelation, indexRelationInfo);
+ }
+}
+
/*
* Find the tuple that violates the passed unique index (conflictindex).
*
*conflictslot = NULL;
+ /*
+ * Build additional information required to check constraints violations.
+ * See check_exclusion_or_unique_constraint().
+ */
+ BuildConflictIndexInfo(resultRelInfo, conflictindex);
+
retry:
if (ExecCheckIndexConstraints(resultRelInfo, slot, estate,
&conflictTid, &slot->tts_tid,
{
ResultRelInfo *relinfo = edata->targetRelInfo;
- ExecOpenIndices(relinfo, true);
+ ExecOpenIndices(relinfo, false);
apply_handle_insert_internal(edata, relinfo, remoteslot);
ExecCloseIndices(relinfo);
}
MemoryContext oldctx;
EvalPlanQualInit(&epqstate, estate, NULL, NIL, -1, NIL);
- ExecOpenIndices(relinfo, true);
+ ExecOpenIndices(relinfo, false);
found = FindReplTupleInLocalRel(edata, localrel,
&relmapentry->remoterel,
$node_publisher->safe_psql('postgres',
"CREATE TABLE conf_tab (a int PRIMARY KEY, b int UNIQUE, c int UNIQUE);");
+$node_publisher->safe_psql('postgres',
+ "CREATE TABLE conf_tab_2 (a int PRIMARY KEY, b int UNIQUE, c int UNIQUE);");
+
# Create same table on subscriber
$node_subscriber->safe_psql('postgres',
"CREATE TABLE conf_tab (a int PRIMARY key, b int UNIQUE, c int UNIQUE);");
+$node_subscriber->safe_psql(
+ 'postgres', qq[
+ CREATE TABLE conf_tab_2 (a int PRIMARY KEY, b int, c int, unique(a,b)) PARTITION BY RANGE (a);
+ CREATE TABLE conf_tab_2_p1 PARTITION OF conf_tab_2 FOR VALUES FROM (MINVALUE) TO (100);
+]);
+
# Setup logical replication
my $publisher_connstr = $node_publisher->connstr . ' dbname=postgres';
$node_publisher->safe_psql('postgres',
- "CREATE PUBLICATION pub_tab FOR TABLE conf_tab");
+ "CREATE PUBLICATION pub_tab FOR TABLE conf_tab, conf_tab_2");
# Create the subscription
my $appname = 'sub_tab';
pass('multiple_unique_conflicts detected during update');
+# Truncate table to get rid of the error
+$node_subscriber->safe_psql('postgres', "TRUNCATE conf_tab;");
+
+
+##################################################
+# Test multiple_unique_conflicts due to INSERT on a leaf partition
+##################################################
+
+# Insert data in the subscriber table
+$node_subscriber->safe_psql('postgres',
+ "INSERT INTO conf_tab_2 VALUES (55,2,3);");
+
+# Insert data in the publisher table
+$node_publisher->safe_psql('postgres',
+ "INSERT INTO conf_tab_2 VALUES (55,2,3);");
+
+$node_subscriber->wait_for_log(
+ qr/conflict detected on relation \"public.conf_tab_2_p1\": conflict=multiple_unique_conflicts.*
+.*Key already exists in unique index \"conf_tab_2_p1_pkey\".*
+.*Key \(a\)=\(55\); existing local tuple \(55, 2, 3\); remote tuple \(55, 2, 3\).*
+.*Key already exists in unique index \"conf_tab_2_p1_a_b_key\".*
+.*Key \(a, b\)=\(55, 2\); existing local tuple \(55, 2, 3\); remote tuple \(55, 2, 3\)./,
+ $log_offset);
+
+pass('multiple_unique_conflicts detected on a leaf partition during insert');
+
done_testing();