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 1wHq9I-007YdS-0g for pgsql-hackers@arkaria.postgresql.org; Tue, 28 Apr 2026 21:39:20 +0000 Received: from localhost ([127.0.0.1] helo=malur.postgresql.org) by malur.postgresql.org with esmtp (Exim 4.96) (envelope-from ) id 1wHq9H-001C3B-1V for pgsql-hackers@arkaria.postgresql.org; Tue, 28 Apr 2026 21:39:19 +0000 Received: from magus.postgresql.org ([2a02:c0:301:0:ffff::29]) by malur.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.96) (envelope-from ) id 1wHq9H-001C32-0S for pgsql-hackers@lists.postgresql.org; Tue, 28 Apr 2026 21:39:19 +0000 Received: from mail-pj1-x1033.google.com ([2607:f8b0:4864:20::1033]) by magus.postgresql.org with esmtps (TLS1.3) tls TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 (Exim 4.98.2) (envelope-from ) id 1wHq9E-00000003ark-3IVB for pgsql-hackers@lists.postgresql.org; Tue, 28 Apr 2026 21:39:18 +0000 Received: by mail-pj1-x1033.google.com with SMTP id 98e67ed59e1d1-362e30526f8so2439695a91.3 for ; Tue, 28 Apr 2026 14:39:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1777412354; cv=none; d=google.com; s=arc-20240605; b=TypsqyVR66P1YWn6mUw8v2xULH5RHumH6f+L943xSQr8qCPlBl60ZR3capV3o3/ngO RWiBKRBB4h2JYZijzqemonoWJ23SmhrWiPNTUOeF9DK/MCkTbC9bSlstMHYsANItT1vq F/QNVxxgWWww7NmEK6f8hW5LR+CGywOFjx4gjfoTq+/HeQwt53XfvnI4KCen1fWxiEIQ wLAdrgffQgCZ0oXh9I+okUsNwqO+VMh9j2YVx3hp9wMBpMikIrpCY+kMkdQxyFpfopRT Yn60lkMCtCb35hnH7zoD/vIyjLQ6tTp+Ym76C4crTgHkXXa8fT5Lxwq18PK1DYEYC0h3 xoXA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=SlFBAjosKtpwuGcrrMa9HhjItQ/ne35HCPp959k6t8s=; fh=oduc2q4N0WOX54pYcCNBWeCNFOYwbVBalb25NnmoEbs=; b=iTYXhftbhUTLlQdOguxy+dVsx5jGrYp5X8U/HLeyoD7jQzcj/0ZTP7McLKSn7cRPCY IxZCTT3nEr6X5D3kkwHoZxEyMYiaTRLAsRzTCZHolw8bfPZrcKDwlFJ2kwPAP4w0eFzP f6LGO/bfd5SeYsbAC9CLmZGqmiJkCVPynW4xRrKyDiByB/UbvYsMl5p/TR9HO5P5nw0j j4GRWqMDuiAxCW+/jEQCdiUmqK0sWYZF3eP+M3fs35wlKRjA4EjurNwmHczpUOx6T4N+ QYiadBCbFXblFJvV1bRCIsdpNHCmh6dL2GMrW2KW30uSnY8Z60MtEb8foa0Auutjsn7u Odjw==; darn=lists.postgresql.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20251104; t=1777412354; x=1778017154; darn=lists.postgresql.org; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:from:to:cc:subject:date :message-id:reply-to; bh=SlFBAjosKtpwuGcrrMa9HhjItQ/ne35HCPp959k6t8s=; b=OsJIPg1bFO5EGjcmXu9kMlGjL7mxDjSWAFKaor7gkbUewUNkH43oLJEoz3UOrw8Q4h 9rNzf7qN++XKKKPgroqywzr63TseKmG2yxWcsiARcmdXnPC/W+SREnBmzyOsZjo04OiX sRyPIsnwDh6usRLMQt+KmBt1CkbXyjfqGI85SuOElboERH6RjnRP59jfScbi50rXEZ+1 skgzHQfuT+Di/nre59medkU/P8jEfaDPblrOiBKtq9qojE81VL29eH/pmlMKMaHBHQ7y NiWNFDQTyXLI/KXj3gFeY2PALeLU3EuZdfPh45MF7YZKi3zvlhBfiJkmpPHnwmLJu+t5 tdbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1777412354; x=1778017154; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=SlFBAjosKtpwuGcrrMa9HhjItQ/ne35HCPp959k6t8s=; b=J4ssOh7ulSTekZoydU2C4iEK49JqhQqKmoEjlfyqrDdDNNn2xQQjAgC/5qpYxs4iHd 6JMzuGSkETHk8q5rlfCm2rNhCMXwLKstqCpYIIrojRZwrBWSLxmCX9QOrdbL5KG8ZDp2 S+iHgK9W3bDp8jdlJf6uDnNyQkwIvJFYUJ+SSrE0XboN0zjW8t+ctSiu1MB3WyVHkoz/ 9I5X2eUzs2XQVQs+rNefXkhaBO2ERD6dVhuAYzLE/wZy4IFqxgu4PmSYkpfNc/JGaMty MY67cWzAc7ARgcSNWPoahEmZmYGGfrfK2uGKM22YMvXNuelu8eXYWuIkbf6fyt9gFQlk BjvA== X-Forwarded-Encrypted: i=1; AFNElJ8nsPuz2v3GsvujssjYGpmOWt3D7jSqzCfqcdL0uZZ4tm6iclGOdXClkrJmEd7VSRQaBiQPLRtPS/jbEpaR@lists.postgresql.org X-Gm-Message-State: AOJu0YygoiEJQHcwCYJy50TTjnBMlfSyxMfmo6DZVlrPybC1xOviLiOk VviHqevLj1yqa9X6iUyx55ApmVU+k725nqmFVHmCgpgxuWDBAu+Q8hPIRifMtj+g+iAOJzyYwzN 5WxF4JAq/EehzIu4vOEtBiVOANROxmq0= X-Gm-Gg: AeBDieuGuD7B/eXxnP11ICnc1GJtr4Zwf/vV8S0unsgIRA0hTkcTWPj7FrAf1WASyZz PpYrtzZII5PpHBlrcuBb1IE8us4U5Q3uUe5YsSfwiY+3ToAqAS2detF2GVcx6fHTFMPgr+gGGL8 vnY6AdSNzu23EtCKDjOXSVJiJ67xLpDBUkzbxsPpOuZMtE8JpmwDsIlUZ9QTmIeIduw7Ryy9kZy k8YCUHMK+RzOAEvZX+Ap2YakhnOs0FfYmTXV98ZO8mHwJSRtc3zZ8VD3YwjqXXtlIuznmmxNk96 3KzipgoGu92k2jHzASQ9/M6ihJhPfZwIavokWBBT1Z81PBQC/us= X-Received: by 2002:a17:90b:4d:b0:35b:9896:cbcd with SMTP id 98e67ed59e1d1-364a0f5e646mr1019167a91.27.1777412353768; Tue, 28 Apr 2026 14:39:13 -0700 (PDT) MIME-Version: 1.0 References: <080f9394-c127-4cef-865e-10f2f997125c@postgrespro.ru> <38690b0e-f91b-46fa-b72a-57775612e463@postgrespro.ru> In-Reply-To: From: Masahiko Sawada Date: Tue, 28 Apr 2026 14:38:35 -0700 X-Gm-Features: AVHnY4KxTO1NgvbjIr79QPNDynkfmRHV_mN10tzcY27OnVO9qECBgpqdOLa44VU Message-ID: Subject: Re: Support logical replication of DDLs, take2 To: Dilip Kumar Cc: Vitaly Davydov , Ashutosh Bapat , PostgreSQL Hackers Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable List-Id: List-Help: List-Subscribe: List-Post: List-Owner: List-Archive: Archived-At: Precedence: bulk On Sun, Apr 26, 2026 at 11:15=E2=80=AFPM Dilip Kumar wrote: > > On Tue, Apr 21, 2026 at 4:45=E2=80=AFAM Masahiko Sawada wrote: > > > > > We made a lot of effort on this feature through 2022 and 2023, but the > > development is currently inactive. The last patch was submitted on Jul > > 18, 2023. I've reviewed the previous patches and discussions, and I > > would like to summarize how DDL replication was implemented, the main > > reasons it stalled, and propose an alternative design to address those > > problems. > > > > The overall idea of the previous patch set was to implement DDL > > deparsing and utilize it for DDL replication. It converted a parse > > tree into a JSON string. For instance, if a user executes "DROP TABLE > > t1", the deparser generates from its parse tree: > > > > {DROPSTMT :objects (("t1")) :removeType 41 :behavior 0 :missing_ok > > false :concurrent false} > > > > to: > > > > {"fmt": "DROP TABLE %{objidentity}s", "objidentity": "public.t1"} > > > > This JSON string is self-documenting, meaning someone who gets it can > > easily reconstruct the original DDL with schema-qualified object > > names. In a dedicated event trigger for logical replication, we > > deparsed the parse tree of a DDL, wrote it into a WAL record, and then > > the logical decoding processed it similarly to DML changes. > > I think there was also a discussion on whether to use JSON vs the > existing infrastructure of converting nodes to strings. Although the > JSON is standard format and might provide more flexibility using > existing format avoid extra maintence burden. Right, but since the string representation of nodes are major version dependent, we cannot directly send them to subscribers that might be different major versions. > > > While there are several benefits to the JSON data approach mentioned > > in the wiki [1] -- most notably the flexibility to easily remap > > schemas (e.g., mapping "schema A" on the publisher to "schema B" on > > the subscriber) -- there was a major concern: the huge maintenance > > burden. We would need to maintain the JSON serialization code whenever > > creating or modifying parse nodes, regardless of whether the changes > > were related to DDL replication. IIUC, this was the primary reason the > > feature didn't cross the finish line. > > Do you mean that modifying any existing parse node requires changing > the JSON serialization code? But why do we need to do that if that's > not related to DDL? I don't think I understood this point clearly, > can you explain it or point me to the discussion thread? IIUC, many parse nodes need to support JSON serialization even if we only want to support CREATE/ALTER/DROP TABLE commands. This is because these commands can include expressions (e.g., in DEFAULT clauses or CHECK constraints), function calls, and column references. We would need to recursively deparse the entire expression tree. > > > Additionally, I think there is another design issue: it is not > > output-plugin agnostic. Since the deparsed DDL was written by a > > logical-replication-specific event trigger, third-party logical > > decoding plugins cannot easily detect DDL events. Ideally, we should > > write DDL information into a WAL record natively when > > wal_level=3D'logical' (or additionally when a GUC enables DDL events > > WAL-logging) so that all decoding plugins can detect them. This also > > allows us to test DDL logical decoding with test_decoding without > > setting up a full logical replication subscription. > > Yeah, that's a valid point, but I think we could separate the event > trigger logic from the decoding plugins so that it's available for any > other output plugins? Yes, it's possible. But I'm concerned that the operations users (or plugins) would need to enable DDL events would be quite different from capturing DMLs. I'm not sure if it's a good user experience or plugin developer experience that additional steps are required to capture DDL events while changes of INSERT/UPDATE/DELETE/TRUNCATE are passed from the logical decoding by default. > > > To address these two points, I'd like to propose an alternative > > approach: we introduce a new data type, say DDLCommand, that is > > self-contained to represent a DDL (like CollectedCommand), and don't > > rely on event triggers. It would have the command type (and subtype if > > required), the OIDs of the target object and its namespace, and the > > OID of the user who executed the DDL. We write it to a new WAL record > > at appropriate places during DDL execution, and the logical decoding > > layer passes the data to output plugins. That way, any logical > > decoding plugin can detect DDL changes, and it's up to the plugins how > > to decode the DDL information. > > Interesting. I'm trying to figure out exactly when we plan to > construct this new DDLCommand data type? And how would we prepare > this, by converting the internal DDL structures or from parsetree? I'm still unsure what is the best approach but I think we can construct the DDLCommand data from the internal DDL structures, and each DDL command can call the function to write the DDL command information to a WAL record. Regards, --=20 Masahiko Sawada Amazon Web Services: https://aws.amazon.com