Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
53 commits
Select commit Hold shift + click to select a range
f903238
postgres_cdc: add multi-schema support
ness-david-dedu Jul 6, 2026
c38fd7a
postgres_cdc: reject empty quoted schema identifier and fix misleadin…
ness-david-dedu Jul 6, 2026
bda218d
postgres_cdc: add tests/current/ Docker Compose + Taskfile manual tes…
ness-david-dedu Jul 7, 2026
df2dca6
postgres_cdc: add commit_ts_ms and before metadata fields
ness-david-dedu Jul 7, 2026
e6bbd4c
Merge remote-tracking branch 'upstream/main' into feature/postgres_cd…
ness-david-dedu Jul 9, 2026
fcb0427
postgres_cdc: fix lint and docs
ness-david-dedu Jul 10, 2026
7bcc3ac
postgres_cdc: review fixes and test coverage
ness-david-dedu Jul 10, 2026
d39de9a
postgres_cdc: fix tests
ness-david-dedu Jul 13, 2026
5f9a2a8
Merge remote-tracking branch 'upstream/main' into feature/postgres_cd…
ness-david-dedu Jul 13, 2026
0aa387a
test(cdctest): waive tigerbeetle_cdc conformance fields
ness-david-dedu Jul 15, 2026
ba7c384
postgres_cdc: fix lint
ness-david-dedu Jul 15, 2026
bd3e383
Merge remote-tracking branch 'upstream/main' into feature/postgres_cd…
ness-david-dedu Jul 22, 2026
caa0b1a
postgres_cdc: skip missing tables per-schema instead of failing whole…
ness-david-dedu Jul 22, 2026
c161947
postgres_cdc: fix lint
ness-david-dedu Jul 22, 2026
0ed96fd
Update internal/impl/postgresql/pglogicalstream/schema_resolver.go
ness-david-dedu Jul 23, 2026
d893e1a
postgres_cdc: warn when schema pattern matches privilege-hidden schemas
ness-david-dedu Jul 27, 2026
28b2710
Merge branch 'main' into feature/postgres_cdc_multi_schema
josephwoodward Aug 4, 2026
0e662de
postgres_cdc: Address minor issues
josephwoodward Aug 4, 2026
e7dccc6
postgres_cdc: fix broken test
josephwoodward Aug 4, 2026
80e2204
postgres_cdc: replace pg_schema with database_schema
josephwoodward Aug 4, 2026
fc960ce
postgres_cdc: move schema validation to unit test closer to use
josephwoodward Aug 4, 2026
3411584
postgres_cdc: clean up redundant comment
josephwoodward Aug 4, 2026
bf28959
postgres_cdc: normalie test structure
josephwoodward Aug 4, 2026
58d3be8
postgres_cdc: t.Context()
josephwoodward Aug 4, 2026
6803eca
postgres_cdc: revert to existing behaviour
josephwoodward Aug 6, 2026
045cde2
postgres_cdc: improve on missing table coverage
josephwoodward Aug 6, 2026
c9e488b
update docs
josephwoodward Aug 6, 2026
0cd24bd
postgres_cdc: add schema_pattern field for multi-schema replication
ness-david-dedu Aug 10, 2026
33e4049
postgres_cdc: fix unicode schema_pattern rejection, sync changelog
ness-david-dedu Aug 11, 2026
b428bd7
postgres_cdc: fix stale schema_pattern refs in manual test harness
ness-david-dedu Aug 11, 2026
b46a4e5
postgres_cdc: add excluded_schema
ness-david-dedu Aug 11, 2026
dcda716
Merge remote-tracking branch 'upstream/main' into feature/postgres_cd…
ness-david-dedu Aug 11, 2026
7a136ba
postgres_cdc: fix failing signalling tests
josephwoodward Aug 12, 2026
52dbd2b
postgres_cdc: add further test coverage for uuid schemas
josephwoodward Aug 12, 2026
55cf17d
postgres_cdc: adress qupted schema
josephwoodward Aug 12, 2026
f39ff34
postgres_cdc: allow a leading digit for unquoted patterns
josephwoodward Aug 12, 2026
bbf65cd
postgres_cdc: remove now redundant subtests
josephwoodward Aug 12, 2026
715e233
postgres_cdc: ensure we don't discover views
josephwoodward Aug 12, 2026
65b08a9
postgres_cdc: require/assert switch
josephwoodward Aug 12, 2026
6079ef8
postgres_cdc: update docs
josephwoodward Aug 12, 2026
a74fdf7
postgres_cdc: group tables/schema var declarations
ness-david-dedu Aug 13, 2026
24aa2cd
postgres_cdc: auto-discover tables for schema_pattern when tables is …
ness-david-dedu Aug 13, 2026
96b8d78
postgres_cdc: rename schema_pattern/exclude_schemas to schema_include…
ness-david-dedu Aug 13, 2026
9897bbd
postgres_cdc: update docs
josephwoodward Aug 20, 2026
5a78e09
postgres_cdc: update tables docs
josephwoodward Aug 20, 2026
bc81de9
postgres_cdc: clean up testing and validation
josephwoodward Aug 20, 2026
ad32e8e
postgres_cdc: fix link
josephwoodward Aug 20, 2026
6c0ffcb
fix:
josephwoodward Aug 20, 2026
129878a
postgres_cdc: move schema resolution into dedicated file
josephwoodward Aug 21, 2026
ad1c132
clean up
josephwoodward Aug 21, 2026
591d750
postgres_cdc: improve schema discovery on reconnect loops
josephwoodward Aug 21, 2026
0a86a33
clean up logging
josephwoodward Aug 21, 2026
bd0346b
move to package
josephwoodward Aug 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,8 @@ All notable changes to this project will be documented in this file.

### Added

- postgres_cdc: Added a new `schema_include` field accepting a glob pattern (e.g. `tenant_*`), replicating all matching schemas through a single replication slot. Useful for multi-tenant databases where each tenant has its own schema. Leaving `tables` unset auto-discovers every table in each matched schema instead of listing them by hand. The existing `schema` field is unaffected and continues to take a single exact schema name (defaulting to `public`); `schema` and `schema_include` are mutually exclusive. ([@ness-david-dedu](https://github.com/ness-david-dedu), [#4589](https://github.com/redpanda-data/connect/pull/4589))
- postgres_cdc: Added a new `schema_exclude` field to carve exceptions out of a broad `schema_include` (e.g. `schema_include: tenant_*` while skipping `tenant_test`). Accepts the same exact-name/glob/quoted syntax as `schema_include`, matches entries against the already-resolved schema list in memory with no extra database round-trips, and requires `schema_include` to be set. ([@ness-david-dedu](https://github.com/ness-david-dedu), [#4589](https://github.com/redpanda-data/connect/pull/4589))
- aws_dynamodb_cdc: DynamoDB CDC now supports an optional checkpoint_namespace field, allowing multiple independent pipelines to share a single checkpoint table without overwriting each other's checkpoints. ([@squiidz](https://github.com/squiidz), [#4602](https://github.com/redpanda-data/connect/pull/4602))

### Fixed
Expand Down
81 changes: 74 additions & 7 deletions docs/modules/components/pages/inputs/postgres_cdc.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,10 @@ input:
include_transaction_markers: false
stream_snapshot: false
snapshot_batch_size: 1000
schema: public # No default (required)
tables: [] # No default (required)
schema: public
schema_include: ""
schema_exclude: []
tables: []
checkpoint_limit: 1024
temporary_slot: false
slot_name: my_test_slot # No default (required)
Expand Down Expand Up @@ -73,8 +75,10 @@ input:
include_transaction_markers: false
stream_snapshot: false
snapshot_batch_size: 1000
schema: public # No default (required)
tables: [] # No default (required)
schema: public
schema_include: ""
schema_exclude: []
tables: []
checkpoint_limit: 1024
temporary_slot: false
slot_name: my_test_slot # No default (required)
Expand Down Expand Up @@ -141,7 +145,7 @@ When set to true, empty messages with operation types BEGIN and COMMIT are gener

=== `stream_snapshot`

When set to true, the plugin will first stream a snapshot of all existing data in the database before streaming changes. In order to use this the tables that are being snapshot MUST have a primary key set so that reading from the table can be parallelized. Note that this has no effect if `tables` is left empty, since the snapshot is only planned for tables listed there.
When set to true, the plugin will first stream a snapshot of all existing data in the database before streaming changes. In order to use this the tables that are being snapshot MUST have a primary key set so that reading from the table can be parallelized. Note that this has no effect if `tables` is left empty and `schema_include` is NOT set, since in that case the snapshot is only planned for tables listed in `tables`. When `schema_include` IS set, leaving `tables` empty auto-discovers tables to snapshot instead - see `tables` below - and every discovered table must have a primary key.


*Type*: `bool`
Expand Down Expand Up @@ -176,6 +180,7 @@ The PostgreSQL schema from which to replicate data.

*Type*: `string`

*Default*: `"public"`

```yml
# Examples
Expand All @@ -185,15 +190,77 @@ schema: public
schema: '"MyCaseSensitiveSchemaNeedingQuotes"'
```

=== `schema_include`

The PostgreSQL schema pattern to replicate data from. Accepts an exact schema name or a glob pattern using `*` as a wildcard to match multiple schemas.

When a pattern is used, all schemas whose names match the pattern are replicated using a single replication slot and publication. This is useful for multi-tenant databases where each tenant has its own schema (e.g. `tenant_*` matches `tenant_foo`, `tenant_bar`, etc.).

Double-quoted identifiers are treated as exact names and do not support wildcards.

Schema pattern matching is re-evaluated every time the connector connects or reconnects - including the automatic reconnects that follow a transient replication failure - not just once at pipeline startup. This has two consequences that are easy to miss:

- A schema created after the pipeline started that matches the pattern is picked up on the next reconnect and its tables are added to the publication. However, because the replication slot already exists by then, those tables are treated as already caught up, so with `stream_snapshot` enabled the rows that existed in that schema before it was picked up are never snapshotted and are silently missing from the output - only changes made after the schema is picked up are streamed.
- A schema that is dropped, renamed, or loses its `USAGE` grant between reconnects stops matching and its tables are silently removed from the publication on the next reconnect. A warning is logged when a schema becomes inaccessible due to a lost `USAGE` grant, but that warning is about the schema being inaccessible - it is not logged for a dropped or renamed schema, and nothing is ever logged about the resulting publication drop itself.

If this pattern matches no schema in the database, startup fails with an error - this holds whether or not `tables` is set. See `tables` below for what happens when it's left empty.

This pattern can contain characters that wouldn't be allowed in an unquoted schema name, because it's only ever compared against the real name of each schema in the database - it doesn't have to be a valid name itself. For example, a schema literally named `a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11` (which must have been created using double quotes, since hyphens aren't allowed in an unquoted `CREATE SCHEMA` statement) can still be matched using the unquoted pattern `a0eebc99-*`.

This field is mutually exclusive with `schema`; when set, it takes over schema resolution entirely and `schema` must be left at its default.


*Type*: `string`

*Default*: `""`

```yml
# Examples

schema_include: tenant_*

schema_include: '*'

schema_include: '"MyCaseSensitiveSchemaNeedingQuotes"'
```

=== `schema_exclude`

A list of schema names or glob patterns to exclude from the schemas matched by `schema_include`. Only valid when `schema_include` is set.

Each entry uses the same syntax as `schema_include`: an exact schema name, a glob pattern using `*` as a wildcard, or a double-quoted exact identifier for an exact, case-sensitive match.

A schema that matches `schema_include` and also matches any entry in this list is excluded from replication. An entry that does not match any schema resolved by `schema_include` is silently ignored, so a typo here simply excludes nothing rather than failing startup.

This exclusion is applied before `tables` is resolved, so it also takes effect when `tables` is left empty and tables are auto-discovered.


*Type*: `array`

*Default*: `[]`

```yml
# Examples

schema_exclude:
- tenant_internal
- tenant_test_*
```

=== `tables`

A list of table names to include in the logical replication. Each table should be specified as a separate item.

If left empty, the underlying PostgreSQL publication is created `FOR ALL TABLES`, which replicates every table in every schema of the database, ignoring `schema`. This also disables `stream_snapshot`, since the initial snapshot is only planned for tables listed here.
When `schema_include` is set, this list is resolved against each matched schema independently: a table missing from some (but not all) of the matched schemas is skipped for those schemas only (with a warning logged), tolerating multi-tenant setups where a table hasn't been provisioned in every schema yet. A table that's missing from every matched schema, however, is treated as a configuration error (most likely a typo) and startup fails, naming the missing table.

If left empty while `schema_include` is set, every base table in each matched (and un-excluded, see `schema_exclude`) schema is auto-discovered and published explicitly, instead of listing tables by hand - this is the expected way to replicate "every table" in a multi-tenant, schema-per-tenant setup without also picking up unrelated schemas. Startup fails if no matched schema contains any table.

If left empty while `schema_include` is NOT set, the underlying PostgreSQL publication is instead created `FOR ALL TABLES`, which replicates every table in every schema of the database, ignoring `schema`. This also disables `stream_snapshot`, since the initial snapshot is only planned for tables listed here.


*Type*: `array`

*Default*: `[]`

```yml
# Examples
Expand Down Expand Up @@ -566,7 +633,7 @@ Optional external ID for the role assumption.

=== `signal_table_name`

The name of the table used to send control signals to the connector, excluding the schema. The table must
The name of the table used to send control signals to the connector, excluding the schema. Not supported when `schema_include` is set, since there is no single schema to anchor the signal table to. The table must
exist in the schema configured via the `schema` field, and must not also appear in `tables`
— the signal table is implicitly added to the publication and excluded from snapshot scans, so listing
it in both places is rejected at startup. It must have at least these columns — startup validation checks
Expand Down
Loading
Loading