This is an automated email from the ASF dual-hosted git repository.

davidzollo pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/seatunnel.git


The following commit(s) were added to refs/heads/dev by this push:
     new 65793d174b [Feature][Connector-v2][Postgres-CDC] Allow replica 
identity other than full (#10334)
65793d174b is described below

commit 65793d174bea1cd4afb7054e55f2d4e2e1038ff9
Author: I Putu Ariyasa <[email protected]>
AuthorDate: Tue May 26 21:14:10 2026 +0700

    [Feature][Connector-v2][Postgres-CDC] Allow replica identity other than 
full (#10334)
---
 docs/en/connectors/source/PostgreSQL-CDC.md        |   3 +-
 docs/zh/connectors/source/PostgreSQL-CDC.md        |   3 +-
 .../config/PostgresIncrementalSourceOptions.java   |  11 +++
 .../cdc/postgres/source/PostgresDialect.java       |  12 ++-
 .../postgres/source/PostgresIncrementalSource.java |  15 ++-
 .../source/PostgresIncrementalSourceFactory.java   |   1 +
 .../cdc/postgres/source/PostgresDialectTest.java   | 108 +++++++++++++++++++++
 7 files changed, 148 insertions(+), 5 deletions(-)

diff --git a/docs/en/connectors/source/PostgreSQL-CDC.md 
b/docs/en/connectors/source/PostgreSQL-CDC.md
index 89424a4a61..742aadbe61 100644
--- a/docs/en/connectors/source/PostgreSQL-CDC.md
+++ b/docs/en/connectors/source/PostgreSQL-CDC.md
@@ -55,7 +55,7 @@ ALTER SYSTEM SET wal_level TO 'logical';
 SELECT pg_reload_conf();
 ```
 
-2. Change the REPLICA policy of the specified table to FULL
+2. Change the REPLICA policy of the specified table to FULL, unless 
`require-replica-identity-full` is set to `false`.
 
 ```sql
 ALTER TABLE your_table_name REPLICA IDENTITY FULL;
@@ -112,6 +112,7 @@ ALTER TABLE your_table_name REPLICA IDENTITY FULL;
 | split.allow-sampling                      | Boolean  | No       | true     | 
Whether to allow sampling-based sharding strategy. When set to false, the 
system will fall back to unevenly-sized chunk splitting (iterative query 
approach) regardless of the shard count. The default value is true. |
 | exactly_once                              | Boolean  | No       | false    | 
Enable exactly once semantic.                                                   
                                                                                
                                                                                
                                                                                
                                                                                
              [...]
 | format                                    | Enum     | No       | DEFAULT  | 
Optional output format for PostgreSQL CDC, valid enumerations are `DEFAULT`, 
`COMPATIBLE_DEBEZIUM_JSON`.                                                     
                                                                                
                                                                                
                                                                                
                 [...]
+| require-replica-identity-full             | Boolean  | No       | true     | 
Require the table to have REPLICA IDENTITY FULL. When set to false, allows 
tables with other replica identity settings, but UPDATE/DELETE events may not 
contain the previous state. This should only be used for append-only tables 
(e.g., outbox pattern). Default is true for backward compatibility.             
                                                                                
                         [...]
 | debezium                                  | Config   | No       | -        | 
Pass-through [Debezium's 
properties](https://github.com/debezium/debezium/blob/v1.9.8.Final/documentation/modules/ROOT/pages/connectors/postgresql.adoc#connector-configuration-properties)
 to Debezium Embedded Engine which is used to capture data changes from 
PostgreSQL server.                                                              
                                                                           [...]
 | common-options                            |          | no       | -        | 
Source plugin common parameters, please refer to [Source Common 
Options](../common-options/source-common-options.md) for details                
                                                                                
                                                                                
                                                                                
                              [...]
 
diff --git a/docs/zh/connectors/source/PostgreSQL-CDC.md 
b/docs/zh/connectors/source/PostgreSQL-CDC.md
index 9ca3f5df32..6da31a81c9 100644
--- a/docs/zh/connectors/source/PostgreSQL-CDC.md
+++ b/docs/zh/connectors/source/PostgreSQL-CDC.md
@@ -53,7 +53,7 @@ ALTER SYSTEM SET wal_level TO 'logical';
 SELECT pg_reload_conf();
 ```
 
-2. 将指定表的 REPLICA 策略更改为 FULL
+2. 将指定表的 REPLICA 策略更改为 FULL,除非 `require-replica-identity-full` 设置为 `false`。
 
 ```sql
 ALTER TABLE your_table_name REPLICA IDENTITY FULL;
@@ -110,6 +110,7 @@ ALTER TABLE your_table_name REPLICA IDENTITY FULL;
 | split.allow-sampling                      | Boolean  | 否   | true     | 
是否允许基于采样的分片策略。当设置为 false 时,无论预估分片数是否超过阈值,系统都将回退到非均匀分片方式(迭代查询方式)。默认值为 true。 |
 | exactly_once                              | Boolean  | 否   | false    | 
启用精确一次语义。                                                                       
                                                                                
                                                                                
                                                                                
                                                                                
                   [...]
 | format                                    | Enum     | 否   | DEFAULT  | 
PostgreSQL CDC 的可选输出格式,有效枚举为 `DEFAULT`、`COMPATIBLE_DEBEZIUM_JSON`。              
                                                                                
                                                                                
                                                                                
                                                                                
                   [...]
+| require-replica-identity-full             | Boolean  | 否   | true     | 
要求表具有 REPLICA IDENTITY FULL。设置为 false 时,允许表使用其他副本标识设置,但 UPDATE/DELETE 
事件可能不包含之前的状态。此选项仅应用于仅追加的表(例如 outbox 模式)。默认为 true 以保持向后兼容性。                      
                                                                                
                                                                                
                                                                                
                             [...]
 | debezium                                  | Config   | 否   | -        | 将 
[Debezium 
的属性](https://github.com/debezium/debezium/blob/v1.9.8.Final/documentation/modules/ROOT/pages/connectors/postgresql.adoc#connector-configuration-properties)
 传递给用于捕获 PostgreSQL 服务器数据更改的 Debezium 嵌入式引擎。                                    
                                                                                
                                                                                
            [...]
 | common-options                            |          | 否   | -        | 
源插件的公共参数,请参阅 [源公共选项](../common-options/source-common-options.md) 获取详细信息。        
                                                                                
                                                                                
                                                                                
                                                                                
                   [...]
 
diff --git 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/config/PostgresIncrementalSourceOptions.java
 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/config/PostgresIncrementalSourceOptions.java
index bf28d79938..330a31bf34 100644
--- 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/config/PostgresIncrementalSourceOptions.java
+++ 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/config/PostgresIncrementalSourceOptions.java
@@ -48,4 +48,15 @@ public class PostgresIncrementalSourceOptions extends 
JdbcSourceOptions {
                     .listType()
                     .noDefaultValue()
                     .withDescription("Schema name of the database to 
monitor.");
+
+    public static final Option<Boolean> REQUIRE_REPLICA_IDENTITY_FULL =
+            Options.key("require-replica-identity-full")
+                    .booleanType()
+                    .defaultValue(true)
+                    .withDescription(
+                            "Require the table to have REPLICA IDENTITY FULL. "
+                                    + "When set to false, allows tables with 
other replica identity settings, "
+                                    + "but UPDATE/DELETE events may not 
contain the previous state. "
+                                    + "This should only be used for 
append-only tables (e.g., outbox pattern). "
+                                    + "Default is true for backward 
compatibility.");
 }
diff --git 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresDialect.java
 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresDialect.java
index 921cb52518..0af26e71df 100644
--- 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresDialect.java
+++ 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresDialect.java
@@ -66,6 +66,7 @@ public class PostgresDialect implements JdbcDataSourceDialect 
{
     private PostgresWalFetchTask postgresWalFetchTask;
 
     private final Map<TableId, CatalogTable> tableMap;
+    private boolean requireReplicaIdentityFull = true;
 
     public PostgresDialect(
             PostgresSourceConfigFactory configFactory, List<CatalogTable> 
catalogTables) {
@@ -73,6 +74,14 @@ public class PostgresDialect implements 
JdbcDataSourceDialect {
         this.tableMap = CatalogTableUtils.convertTables(catalogTables);
     }
 
+    protected PostgresDialect(
+            PostgresSourceConfigFactory configFactory,
+            List<CatalogTable> catalogTables,
+            boolean requireReplicaIdentityFull) {
+        this(configFactory, catalogTables);
+        this.requireReplicaIdentityFull = requireReplicaIdentityFull;
+    }
+
     @Override
     public String getName() {
         return DatabaseIdentifier.POSTGRESQL;
@@ -121,7 +130,8 @@ public class PostgresDialect implements 
JdbcDataSourceDialect {
         for (TableId tableId : tableIds) {
             ServerInfo.ReplicaIdentity replicaIdentity =
                     postgresConnection.readReplicaIdentityInfo(tableId);
-            if (!ServerInfo.ReplicaIdentity.FULL.equals(replicaIdentity)) {
+            if (requireReplicaIdentityFull
+                    && 
!ServerInfo.ReplicaIdentity.FULL.equals(replicaIdentity)) {
                 throw new SeaTunnelException(
                         String.format(
                                 "Table %s does not have a full replica 
identity, please execute: ALTER TABLE %s REPLICA IDENTITY FULL;",
diff --git 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresIncrementalSource.java
 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresIncrementalSource.java
index a9e10e9516..38074fae78 100644
--- 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresIncrementalSource.java
+++ 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresIncrementalSource.java
@@ -35,6 +35,7 @@ import 
org.apache.seatunnel.connectors.cdc.debezium.DebeziumDeserializationSchem
 import org.apache.seatunnel.connectors.cdc.debezium.DeserializeFormat;
 import 
org.apache.seatunnel.connectors.cdc.debezium.row.DebeziumJsonDeserializeSchema;
 import 
org.apache.seatunnel.connectors.cdc.debezium.row.SeaTunnelRowDebeziumDeserializeSchema;
+import 
org.apache.seatunnel.connectors.seatunnel.cdc.postgres.config.PostgresIncrementalSourceOptions;
 import 
org.apache.seatunnel.connectors.seatunnel.cdc.postgres.config.PostgresSourceConfigFactory;
 import 
org.apache.seatunnel.connectors.seatunnel.cdc.postgres.source.offset.LsnOffsetFactory;
 import org.apache.seatunnel.connectors.seatunnel.jdbc.config.JdbcCommonOptions;
@@ -59,8 +60,12 @@ public class PostgresIncrementalSource<T> extends 
IncrementalSource<T, JdbcSourc
 
     static final String IDENTIFIER = "Postgres-CDC";
 
+    private final boolean requireReplicaIdentityFull;
+
     public PostgresIncrementalSource(ReadonlyConfig options, 
List<CatalogTable> catalogTables) {
         super(options, catalogTables);
+        this.requireReplicaIdentityFull =
+                
options.get(PostgresIncrementalSourceOptions.REQUIRE_REPLICA_IDENTITY_FULL);
     }
 
     @Override
@@ -115,7 +120,10 @@ public class PostgresIncrementalSource<T> extends 
IncrementalSource<T, JdbcSourc
 
     @Override
     public DataSourceDialect<JdbcSourceConfig> 
createDataSourceDialect(ReadonlyConfig config) {
-        return new PostgresDialect((PostgresSourceConfigFactory) 
configFactory, catalogTables);
+        return new PostgresDialect(
+                (PostgresSourceConfigFactory) configFactory,
+                catalogTables,
+                requireReplicaIdentityFull);
     }
 
     @Override
@@ -132,7 +140,10 @@ public class PostgresIncrementalSource<T> extends 
IncrementalSource<T, JdbcSourc
     private Map<TableId, Struct> tableChanges() {
         JdbcSourceConfig jdbcSourceConfig = configFactory.create(0);
         PostgresDialect dialect =
-                new PostgresDialect((PostgresSourceConfigFactory) 
configFactory, catalogTables);
+                new PostgresDialect(
+                        (PostgresSourceConfigFactory) configFactory,
+                        catalogTables,
+                        requireReplicaIdentityFull);
         List<TableId> discoverTables = 
dialect.discoverDataCollections(jdbcSourceConfig);
         SchemaNameAdjuster adjuster = SchemaNameAdjuster.create();
         ConnectTableChangeSerializer connectTableChangeSerializer =
diff --git 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresIncrementalSourceFactory.java
 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresIncrementalSourceFactory.java
index ed1c52d349..d4aefa4139 100644
--- 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresIncrementalSourceFactory.java
+++ 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresIncrementalSourceFactory.java
@@ -67,6 +67,7 @@ public class PostgresIncrementalSourceFactory implements 
TableSourceFactory {
                         JdbcSourceOptions.CONNECTION_POOL_SIZE,
                         PostgresIncrementalSourceOptions.DECODING_PLUGIN_NAME,
                         PostgresIncrementalSourceOptions.SLOT_NAME,
+                        
PostgresIncrementalSourceOptions.REQUIRE_REPLICA_IDENTITY_FULL,
                         
JdbcSourceOptions.CHUNK_KEY_EVEN_DISTRIBUTION_FACTOR_LOWER_BOUND,
                         
JdbcSourceOptions.CHUNK_KEY_EVEN_DISTRIBUTION_FACTOR_UPPER_BOUND,
                         JdbcSourceOptions.SAMPLE_SHARDING_THRESHOLD,
diff --git 
a/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/test/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresDialectTest.java
 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/test/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresDialectTest.java
new file mode 100644
index 0000000000..5cd1649d38
--- /dev/null
+++ 
b/seatunnel-connectors-v2/connector-cdc/connector-cdc-postgres/src/test/java/org/apache/seatunnel/connectors/seatunnel/cdc/postgres/source/PostgresDialectTest.java
@@ -0,0 +1,108 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.seatunnel.connectors.seatunnel.cdc.postgres.source;
+
+import org.apache.seatunnel.common.utils.SeaTunnelException;
+import 
org.apache.seatunnel.connectors.seatunnel.cdc.postgres.config.PostgresSourceConfigFactory;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import io.debezium.connector.postgresql.connection.PostgresConnection;
+import io.debezium.connector.postgresql.connection.ServerInfo;
+import io.debezium.jdbc.JdbcConfiguration;
+import io.debezium.relational.TableId;
+
+import java.sql.SQLException;
+import java.util.Collections;
+import java.util.List;
+
+public class PostgresDialectTest {
+    private static class TestPostgresConnection extends PostgresConnection {
+
+        private final ServerInfo.ReplicaIdentity identity;
+
+        public TestPostgresConnection(ServerInfo.ReplicaIdentity identity) {
+            super(JdbcConfiguration.empty(), "test");
+            this.identity = identity;
+        }
+
+        @Override
+        public ServerInfo.ReplicaIdentity readReplicaIdentityInfo(TableId 
tableId) {
+            return identity;
+        }
+    }
+
+    @Test
+    public void shouldThrowWhenNotFullAndRequired() throws SQLException {
+        PostgresSourceConfigFactory configFactory =
+                (PostgresSourceConfigFactory)
+                        new PostgresSourceConfigFactory()
+                                .hostname("localhost")
+                                .username("user")
+                                .password("password")
+                                .databaseList("database");
+
+        List<TableId> tableIds =
+                Collections.singletonList(new TableId("catalog", "schema", 
"table"));
+
+        PostgresConnection conn = new 
TestPostgresConnection(ServerInfo.ReplicaIdentity.DEFAULT);
+        PostgresDialect dialect = new PostgresDialect(configFactory, 
Collections.emptyList());
+
+        Assertions.assertThrows(
+                SeaTunnelException.class,
+                () -> dialect.checkAllTablesEnabledCapture(conn, tableIds));
+    }
+
+    @Test
+    public void shouldNotThrowWhenFullAndRequired() throws SQLException {
+        PostgresSourceConfigFactory configFactory =
+                (PostgresSourceConfigFactory)
+                        new PostgresSourceConfigFactory()
+                                .hostname("localhost")
+                                .username("user")
+                                .password("password")
+                                .databaseList("database");
+
+        List<TableId> tableIds =
+                Collections.singletonList(new TableId("catalog", "schema", 
"table"));
+
+        PostgresConnection conn = new 
TestPostgresConnection(ServerInfo.ReplicaIdentity.FULL);
+        PostgresDialect dialect = new PostgresDialect(configFactory, 
Collections.emptyList());
+        Assertions.assertDoesNotThrow(() -> 
dialect.checkAllTablesEnabledCapture(conn, tableIds));
+    }
+
+    @Test
+    public void shouldNotThrowWhenNotFullAndNotRequired() throws SQLException {
+        PostgresSourceConfigFactory configFactory =
+                (PostgresSourceConfigFactory)
+                        new PostgresSourceConfigFactory()
+                                .hostname("localhost")
+                                .username("user")
+                                .password("password")
+                                .databaseList("database");
+
+        List<TableId> tableIds =
+                Collections.singletonList(new TableId("catalog", "schema", 
"table"));
+
+        PostgresDialect dialect =
+                new PostgresDialect(configFactory, Collections.emptyList(), 
false);
+        PostgresConnection conn = new 
TestPostgresConnection(ServerInfo.ReplicaIdentity.DEFAULT);
+        Assertions.assertDoesNotThrow(() -> 
dialect.checkAllTablesEnabledCapture(conn, tableIds));
+    }
+}

Reply via email to