Re: Support logical replication of DDLs

Vitaly Davydov <v.davydov@postgrespro.ru>

From: Vitaly Davydov <v.davydov@postgrespro.ru>
To: Andreas Karlsson <andreas@proxel.se>, pgsql-hackers@lists.postgresql.org
Date: 2026-02-20T15:07:07Z
Lists: pgsql-hackers, pgsql-general
Hi Andreas,

On 2/9/26 16:40, Andreas Karlsson wrote:
 > With this approach how do you intend to handle DDL changes which alter data?
 > To take a simple case we have the USING clause when altering a column. Maybe
 > it is a fine limitation to just not support it but I am not convinced.

When a column is altered, new tuples with altered data are inserted. Such tuples
are decoded as inserted in logical replication. The pg_attribute change
(ALTER COLUMN) will be decoded first, but inserted tuples will be decoded later.

In another words, I may say that ALTER COLUMN consists of two steps:
(1) create a new column (and drop old column)
(2) insert modified tuples

The USING clause just affects the values of the inserted tuples, I think.

Consider the following original schema with data:
CREATE TABLE t(x int);
INSERT INTO t(x) VALUES(0);
INSERT INTO t(x) VALUES(1);
INSERT INTO t(x) VALUES(2);

When we apply:
ALTER TABLE t ALTER COLUMN x TYPE double precision;

The decoded operation sequence looks like below. In brackets: (txid, cid).

pg_attribute_update (766, 1) rel = t, attname = x, atttypid (new/old): double 
precision / integer
pg_class_insert (766, 2) rel = pg_temp_16384, relkind = r
pg_attribute_insert (766, 2) rel = pg_temp_16384, attname = x
...
pg_decode_change (766, 3): rel = t, insert
pg_decode_change (766, 3): rel = t, insert
pg_decode_change (766, 3): rel = t, insert
pg_class_update (766, 3) rel = t, relkind = r, relrewrite: 0
pg_class_update (766, 3) rel = pg_temp_16384, relkind = r, relrewrite: 16384
pg_attribute_delete (766, 6)
...
pg_class_delete
commit_txn

For query:
ALTER TABLE t ALTER COLUMN x TYPE double precision USING (x::double precision + 1.2)
the operation sequence seems to be the same.

By decoding pg_attribute update we decide that ALTER COLUMN is executing.
At first glance, column type change with USING should be easily decoded. I think
the temp table is created here to convert values to the new type, and it should
be ignored when decoding, because new tuple values will be inserted and decoded
as new ones.

With best regards,
Vitaly



Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Add a run_as_owner option to subscriptions.

  2. Refactor pgoutput_change().

  3. Print the correct aliases for DML target tables in ruleutils.

  4. Fix object identity string for transforms

  5. Add grantable MAINTAIN privilege and pg_maintain role.

  6. Get rid of recursion-marker values in enum AlterTableType

  7. Release cache tuple when no longer needed

  8. Empty search_path in logical replication apply worker and walsender.

  9. Refactor format_type APIs to be more modular

  10. Use wrappers of PG_DETOAST_DATUM_PACKED() more.