{"record":{"id":"42eefcaefb6f43c4","repo":"apache/seatunnel","slug":"incremental-snapshot-for-tables-requires-primary-k-42eefc","errorCode":null,"errorMessage":"Incremental snapshot for tables requires primary key, but table %s doesn't have primary key.","messagePattern":"Incremental snapshot for tables requires primary key, but table (.+?) doesn't have primary key\\.","errorType":"exception","errorClass":"SeaTunnelException","httpStatus":null,"severity":"error","filePath":"seatunnel-connectors-v2/connector-cdc/connector-cdc-oracle/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/oracle/utils/OracleUtils.java","lineNumber":350,"sourceCode":"                    statement.setObject(i + 1, splitStart[i]);\n                }\n            } else {\n                for (int i = 0; i < primaryKeyNum; i++) {\n                    statement.setObject(i + 1, splitStart[i]);\n                    statement.setObject(i + 1 + primaryKeyNum, splitEnd[i]);\n                    statement.setObject(i + 1 + 2 * primaryKeyNum, splitEnd[i]);\n                }\n            }\n            return statement;\n        } catch (Exception e) {\n            throw new RuntimeException(\"Failed to build the split data read statement.\", e);\n        }\n    }\n\n    public static SeaTunnelRowType getSplitType(Table table) {\n        List<Column> primaryKeys = table.primaryKeyColumns();\n        if (primaryKeys.isEmpty()) {\n            throw new SeaTunnelException(\n                    String.format(\n                            \"Incremental snapshot for tables requires primary key,\"\n                                    + \" but table %s doesn't have primary key.\",\n                            table.id()));\n        }\n\n        // use first field in primary key as the split key\n        return getSplitType(primaryKeys.get(0));\n    }\n\n    /** Creates a new {@link OracleDatabaseSchema} to monitor the latest oracle database schemas. */\n    public static OracleDatabaseSchema createOracleDatabaseSchema(\n            OracleConnectorConfig dbzOracleConfig, OracleConnection connection) {\n        TopicSelector<TableId> topicSelector = OracleTopicSelector.defaultSelector(dbzOracleConfig);\n        SchemaNameAdjuster schemaNameAdjuster = SchemaNameAdjuster.create();\n        OracleValueConverters oracleValueConverters =\n                new OracleValueConverters(dbzOracleConfig, connection);\n        OracleDefaultValueConverter defaultValueConverter =","sourceCodeStart":332,"sourceCodeEnd":368,"githubUrl":"https://github.com/apache/seatunnel/blob/cf67b549a7a6c35fa0beb12d83c62892427ea919/seatunnel-connectors-v2/connector-cdc/connector-cdc-oracle/src/main/java/org/apache/seatunnel/connectors/seatunnel/cdc/oracle/utils/OracleUtils.java#L332-L368","documentation":"Thrown by OracleUtils.getSplitType when incremental snapshot split computation is requested for a table without primary key columns. Incremental snapshotting chunks data by a primary/split key, so keyless tables are rejected with this SeaTunnelException naming the table.","triggerScenarios":"The table passed to getSplitType (from Debezium schema metadata) has an empty primaryKeyColumns() list, and the job uses incremental snapshot (scan.incremental.snapshot.enabled=true).","commonSituations":"Oracle table created without a PRIMARY KEY constraint; unique index exists but is not declared as a PK so Debezium doesn't report it; snapshotting views or external tables; legacy tables never given keys.","solutions":["Add a primary key to the Oracle table (ALTER TABLE ... ADD PRIMARY KEY).","If a unique non-null column exists, ensure it is declared as PK so Debezium reports it.","Disable incremental snapshot (fall back to the non-parallel snapshot reader) if the table cannot have a key.","Snapshot an alternative table/view that has a proper key."],"exampleFix":"// before\nCREATE TABLE scott.orders (order_id NUMBER, amount NUMBER); // no PK\n// after\nALTER TABLE scott.orders ADD CONSTRAINT pk_orders PRIMARY KEY (order_id);","handlingStrategy":"validation","validationCode":"SELECT cols.column_name\nFROM all_constraints cons\nJOIN all_cons_columns cols ON cons.constraint_name=cols.constraint_name AND cons.owner=cols.owner\nWHERE cons.constraint_type='P' AND cons.owner='SCOTT' AND cons.table_name='ORDERS';","typeGuard":null,"tryCatchPattern":"try {\n    SeaTunnelRowType splitType = OracleUtils.getSplitType(table);\n} catch (SeaTunnelException e) {\n    LOG.warn(\"table {} has no PK: falling back to non-incremental snapshot\", table.id());\n}","preventionTips":["Declare PRIMARY KEY on every table listed for incremental snapshot","Convert unique indexes into real PK constraints","Disable scan.incremental.snapshot.enabled for keyless tables","Grant connector user access to constraint dictionary views"],"tags":["oracle","cdc","primary-key","incremental-snapshot"],"backgroundTag":"missing-primary-key","analyzedSha":"cf67b549a7a6c35fa0beb12d83c62892427ea919","analyzedAt":"2026-09-10T21:44:55.265Z","contentChangedAt":"2026-09-10T21:44:55.265Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}