Received: from malur.postgresql.org ([217.196.149.56]) by arkaria.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vtS6A-008blC-2c for pgsql-hackers@arkaria.postgresql.org; Fri, 20 Feb 2026 15:07:19 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1vtS68-008Jxv-0x for pgsql-hackers@arkaria.postgresql.org; Fri, 20 Feb 2026 15:07:16 +0000 Received: from makus.postgresql.org ([2001:4800:3e1:1::229]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1vtS67-008Jxn-2k for pgsql-hackers@lists.postgresql.org; Fri, 20 Feb 2026 15:07:16 +0000 Received: from mail.postgrespro.ru ([93.174.132.70]) by makus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.98.2) (envelope-from ) id 1vtS63-00000000Nct-2s6S for pgsql-hackers@lists.postgresql.org; Fri, 20 Feb 2026 15:07:14 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=postgrespro.ru; s=mx2023; t=1771600028; bh=ZC1vs4KizoUSk3Omg9iRjv0LDuplQ8FoAdtnqPjPpBs=; h=Message-ID:Date:User-Agent:Subject:To:References:From:In-Reply-To: From; b=cTsySI+XEI9Q7aJ/exQAmDMu9zZMnsiU3mVwPER86EK+Al5KeUXYscm4XJQ5BB0cJ dELgQ3HqzKIhpqxMkYMr+NONhdbrHqwmECHFxmOCvrqiUqdHWhr7I9OLphzAUzWG/u Bl7Q7FWmGVreW0Jog8zNjoo2584SaC9Xajg7O5wmaPHX60aXnDb5kZVKJX+n58IcCB EwfzfZhJJERZMnjv1Kdz7/TpqHz9muFCbzfjaUo4Ar869qe8Yc90qRdEGbj/rwjcSu t9QWDmOnK7l6FkksjP+WqE0ZEfWrgCTTvhjx0FtSMlXIlLcx03Wbh1IA6df+vOIpoP fhTnDCFlYki2w== Received: from [172.30.49.254] (debian11-template.l.postgrespro.ru [192.168.2.254]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (Client did not present a certificate) (Authenticated sender: v.davydov@postgrespro.ru) by mail.postgrespro.ru (Postfix/465) with ESMTPSA id 39D6B60B61; Fri, 20 Feb 2026 18:07:08 +0300 (MSK) Message-ID: <3422e652-48a8-437b-aeaf-6b0d4f5655bb@postgrespro.ru> Date: Fri, 20 Feb 2026 18:07:07 +0300 MIME-Version: 1.0 User-Agent: Mozilla Thunderbird Subject: Re: Support logical replication of DDLs To: Andreas Karlsson , pgsql-hackers@lists.postgresql.org References: <080f9394-c127-4cef-865e-10f2f997125c@postgrespro.ru> Content-Language: en-US From: Vitaly Davydov In-Reply-To: Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-KSMG-AntiPhishing: NotDetected X-KSMG-AntiSpam-Interceptor-Info: not scanned X-KSMG-AntiSpam-Status: not scanned, disabled by settings X-KSMG-AntiVirus: Kaspersky Secure Mail Gateway, version 2.1.0.7854, bases: 2026/02/20 14:05:00 #28208031 X-KSMG-AntiVirus-Status: NotDetected, skipped X-KSMG-LinksScanning: not scanned, disabled by settings X-KSMG-Message-Action: skipped X-KSMG-Rule-ID: 1 List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk 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